TextModel - Shape the given number of characters inside a text. 66/61066/4
authorVictor Cebollada <v.cebollada@samsung.com>
Thu, 3 Mar 2016 09:14:34 +0000 (09:14 +0000)
committerVictor Cebollada <v.cebollada@samsung.com>
Tue, 8 Mar 2016 16:13:22 +0000 (16:13 +0000)
Change-Id: I8936449b132cfaf28941af58f19e06536297815e
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
automated-tests/src/dali-toolkit-internal/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp
dali-toolkit/internal/text/shaper.cpp
dali-toolkit/internal/text/shaper.h
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/text/visual-model-impl.h

index 7e21216..0852234 100644 (file)
@@ -13,6 +13,8 @@ SET(TC_SOURCES
  utc-Dali-Text-MultiLanguage.cpp
  utc-Dali-LogicalModel.cpp
  utc-Dali-BidirectionalSupport.cpp
+ utc-Dali-Text-Shaping.cpp
+ utc-Dali-VisualModel.cpp
 )
 
 # Append list of test harness files (Won't get parsed for test cases)
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp
new file mode 100644 (file)
index 0000000..0dd3144
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-model.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following function.
+// void ShapeText( const Vector<Character>& text,
+//                 const Vector<LineBreakInfo>& lineBreakInfo,
+//                 const Vector<ScriptRun>& scripts,
+//                 const Vector<FontRun>& fonts,
+//                 CharacterIndex startCharacterIndex,
+//                 GlyphIndex startGlyphIndex,
+//                 Length numberOfCharacters,
+//                 Vector<GlyphInfo>& glyphs,
+//                 Vector<CharacterIndex>& glyphToCharacterMap,
+//                 Vector<Length>& charactersPerGlyph,
+//                 Vector<GlyphIndex>& newParagraphGlyphs );
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct GlyphInfoData
+{
+  FontId fontId;     ///< Identifies the font containing the glyph
+  GlyphIndex index;  ///< Uniquely identifies a glyph for a given FontId
+  float width;       ///< The width of the glyph
+  float height;      ///< The height of the glyph
+  float xBearing;    ///< The distance from the cursor position to the leftmost border of the glyph
+  float yBearing;    ///< The distance from the baseline to the topmost border of the glyph
+  float advance;     ///< The distance to move the cursor for this glyph
+  float scaleFactor; ///< The scaling applied (fixed-size fonts only)
+};
+
+bool IsEqualGlyph ( const GlyphInfoData& glyphData, const GlyphInfo& glyph )
+{
+  if( glyphData.fontId != glyph.fontId )
+  {
+    return false;
+  }
+  if( glyphData.index != glyph.index )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.width - glyph.width ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.height - glyph.height ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.xBearing - glyph.xBearing ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.yBearing - glyph.yBearing ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.advance - glyph.advance ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.scaleFactor - glyph.scaleFactor ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+struct ShapeInfoData
+{
+  std::string     description;                        ///< Description of the test.
+  std::string     text;                               ///< input text.
+  uint32_t        index;                              ///< The index from where to start to query the break info.
+  uint32_t        numberOfCharacters;                 ///< The requested number of characters.
+  uint32_t        expectedNumberOfGlyphs;             ///< The expected number of glyphs.
+  GlyphInfoData*  glyphs;                             ///< The glyphs.
+  CharacterIndex* characterIndices;                   ///< The character index for each glyph.
+  Length*         charactersPerGlyph;                 ///< The characters per glyph.
+  uint32_t        expectedNumberOfNewParagraphGlyphs; ///< The expected number of glyphs.
+  GlyphIndex*     newParagraphGlyphs;                 ///< Indices to the new paragraphs glyphs.
+};
+
+bool ShapeInfoTest( const ShapeInfoData& data )
+{
+  // 1) Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  CreateTextModel( data.text,
+                   textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  // 2) Clear the model.
+
+  Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
+  Vector<CharacterIndex>& glyphToCharacter = visualModel->mGlyphsToCharacters;
+  Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+  Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+
+  // Get the glyph index.
+  GlyphIndex glyphIndex = 0u;
+  if( 0u != visualModel->mCharactersToGlyph.Count() )
+  {
+    glyphIndex = *( visualModel->mCharactersToGlyph.Begin() + data.index );
+
+    const CharacterIndex lastCharacterIndex = data.index + data.numberOfCharacters - 1u;
+    const Length numberOfGlyphs = *( visualModel->mCharactersToGlyph.Begin() + lastCharacterIndex ) + *( visualModel->mGlyphsPerCharacter.Begin() + lastCharacterIndex ) - glyphIndex;
+
+    // Erase the glyph info from the text model.
+    // Got from the ShapeText() function.
+    glyphs.Erase( glyphs.Begin() + glyphIndex, glyphs.Begin() + glyphIndex + numberOfGlyphs );
+    glyphToCharacter.Erase( glyphToCharacter.Begin() + glyphIndex, glyphToCharacter.Begin() + glyphIndex + numberOfGlyphs );
+    charactersPerGlyph.Erase( charactersPerGlyph.Begin() + glyphIndex, charactersPerGlyph.Begin() + glyphIndex + numberOfGlyphs );
+
+    // Got from the VisualModel::CreateCharacterToGlyphTable() and the VisualModel::CreateGlyphsPerCharacterTable() methods.
+    charactersToGlyph.Erase( charactersToGlyph.Begin() + data.index,
+                             charactersToGlyph.Begin() + data.index + data.numberOfCharacters );
+    glyphsPerCharacter.Erase( glyphsPerCharacter.Begin() + data.index,
+                              glyphsPerCharacter.Begin() + data.index + data.numberOfCharacters );
+
+    // Update the glyph to character indices.
+    for( Vector<CharacterIndex>::Iterator it = glyphToCharacter.Begin() + glyphIndex,
+           endIt = glyphToCharacter.End();
+         it != endIt;
+         ++it )
+    {
+      CharacterIndex& index = *it;
+      index -= data.numberOfCharacters;
+    }
+
+  }
+
+  // Reset the metrics got from the model as the ShapeText() function doesn't retrieve them.
+  for( Vector<GlyphInfo>::Iterator it = glyphs.Begin(),
+         endIt = glyphs.End();
+       it != endIt;
+       ++it )
+  {
+    GlyphInfo& info = *it;
+    info.width = 0.f;
+    info.height = 0.f;
+    info.xBearing = 0.f;
+    info.yBearing = 0.f;
+    info.scaleFactor = 0.f;
+  }
+
+  // 3) Call the ShapeText() function.
+
+  Vector<GlyphIndex> newParagraphGlyphs;
+
+  ShapeText( logicalModel->mText,
+             logicalModel->mLineBreakInfo,
+             logicalModel->mScriptRuns,
+             logicalModel->mFontRuns,
+             data.index,
+             glyphIndex,
+             data.numberOfCharacters,
+             glyphs,
+             glyphToCharacter,
+             charactersPerGlyph,
+             newParagraphGlyphs );
+
+  // Clear the advance of the new paragraph glyphs.
+  for( Vector<GlyphIndex>::Iterator it = newParagraphGlyphs.Begin(),
+         endIt = newParagraphGlyphs.End();
+       it != endIt;
+       ++it )
+  {
+    GlyphInfo& info = *( glyphs.Begin() + *it );
+    info.advance = 0.f;
+  }
+
+  // 4) Compare the results.
+
+  if( data.expectedNumberOfGlyphs != glyphs.Count() )
+  {
+    std::cout << "  Different number of glyphs : " << glyphs.Count() << ", expected : " << data.expectedNumberOfGlyphs << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index )
+  {
+    if( !IsEqualGlyph( data.glyphs[index], glyphs[index] ) )
+    {
+      std::cout << "  different glyph info, index : " << index << std::endl;
+      return false;
+    }
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index )
+  {
+    if( data.characterIndices[index] != glyphToCharacter[index] )
+    {
+      std::cout << "  different character index, index : " << index << std::endl;
+      return false;
+    }
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index )
+  {
+    if( data.charactersPerGlyph[index] != charactersPerGlyph[index] )
+    {
+      std::cout << "  different character per glyph, index : " << index << std::endl;
+      return false;
+    }
+  }
+
+  if( data.expectedNumberOfNewParagraphGlyphs != newParagraphGlyphs.Count() )
+  {
+    std::cout << "  Different number of new paragraph glyphs : " << newParagraphGlyphs.Count() << ", expected : " << data.expectedNumberOfNewParagraphGlyphs << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfNewParagraphGlyphs; ++index )
+  {
+    if( data.newParagraphGlyphs[index] != newParagraphGlyphs[index] )
+    {
+      std::cout << "  different new paragraph glyph, index : " << index << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliTextShape(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextShape");
+
+  struct GlyphInfoData glyphs02[] =
+  {
+    { 1u, 43u, 0.f, 0.f, 0.f, 0.f, 12.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 79u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 79u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 90u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 85u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u, 79u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+  };
+
+  CharacterIndex characterIndices02[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+  Length charactersPerGlyph02[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+
+  struct GlyphInfoData glyphs03[] =
+  {
+    { 1u, 43u, 0.f, 0.f, 0.f, 0.f, 12.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 79u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 79u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 90u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 85u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u, 79u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+    { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+  };
+
+  CharacterIndex characterIndices03[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u };
+  Length charactersPerGlyph03[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+  CharacterIndex newParagraphGlyphs03[] = { 11u, 16u };
+
+  struct GlyphInfoData glyphs04[] =
+  {
+    { 2u, 160u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 2u, 123u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 2u, 153u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 2u, 160u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 2u, 150u, 0.f, 0.f, 0.f, 0.f, 14.f, 0.f },
+    { 2u, 153u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 2u, 160u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 2u, 151u, 0.f, 0.f, 0.f, 0.f, 12.f, 0.f },
+    { 2u, 153u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 2u, 160u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 2u, 147u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 2u, 153u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+  };
+
+  CharacterIndex characterIndices04[] = { 0u, 0u, 0u, 2u, 2u, 2u, 4u, 4u, 4u, 6u, 6u, 6u };
+  Length charactersPerGlyph04[] = { 0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u };
+
+  struct GlyphInfoData glyphs05[] =
+  {
+    { 1u, 47u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 85u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 76u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 83u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 86u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 79u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 85u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 86u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 76u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 87u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 68u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 87u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+    { 1u, 68u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 84u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 5034u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 81u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 76u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 69u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 68u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 86u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 68u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 76u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+    { 1u, 83u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 82u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 86u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 86u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 76u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 85u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u, 68u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 70u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 81u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 76u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 68u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 81u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 72u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 70u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f },
+    { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 1u, 17u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+  };
+
+  CharacterIndex characterIndices05[] = {  0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u,
+                                          10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u,
+                                          20u, 21u, 22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u,
+                                          30u, 31u, 32u, 33u, 34u, 35u, 37u, 38u, 39u, 40u,
+                                          41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u,
+                                          51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u,
+                                          61u, 62u, 63u, 64u, 65u, 66u, 67u, 68u, 69u, 70u,
+                                          71u, 72u, 73u, 74u };
+  Length charactersPerGlyph05[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 2u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u };
+  CharacterIndex newParagraphGlyphs05[] = { 26u };
+  CharacterIndex newParagraphGlyphs06[] = { 49u };
+  CharacterIndex newParagraphGlyphs07[] = { 73u };
+
+  struct ShapeInfoData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      0u,
+      NULL,
+      NULL,
+      NULL,
+      0u,
+      NULL
+    },
+    {
+      "Latin script",
+      "Hello world",
+      0u,
+      11u,
+      11u,
+      glyphs02,
+      characterIndices02,
+      charactersPerGlyph02,
+      0u,
+      NULL
+    },
+    {
+      "Latin script. Some paragraphs.",
+      "Hello world\ndemo\n",
+      0u,
+      17u,
+      17u,
+      glyphs03,
+      characterIndices03,
+      charactersPerGlyph03,
+      2u,
+      newParagraphGlyphs03
+    },
+    {
+      "Malayalam script. More glyphs than characters.",
+      "ജോസോഹോവോ",
+      0u,
+      8u,
+      12u,
+      glyphs04,
+      characterIndices04,
+      charactersPerGlyph04,
+      0u,
+      NULL
+    },
+    {
+      "Latin script with some paragraphs. Update initial paragraph.",
+      "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
+      0u,
+      27u,
+      74u,
+      glyphs05,
+      characterIndices05,
+      charactersPerGlyph05,
+      1u,
+      newParagraphGlyphs05
+    },
+    {
+      "Latin script with some paragraphs. Update mid paragraph.",
+      "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
+      27u,
+      24u,
+      74u,
+      glyphs05,
+      characterIndices05,
+      charactersPerGlyph05,
+      1u,
+      newParagraphGlyphs06
+    },
+    {
+      "Latin script with some paragraphs. Update final paragraph.",
+      "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
+      51u,
+      24u,
+      74u,
+      glyphs05,
+      characterIndices05,
+      charactersPerGlyph05,
+      1u,
+      newParagraphGlyphs07
+    },
+  };
+  const unsigned int numberOfTests = 7u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !ShapeInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp
new file mode 100644 (file)
index 0000000..18faa9e
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-model.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions.
+//
+// void CreateCharacterToGlyphTable( CharacterIndex startIndex,
+//                                   Length numberOfCharacters )
+//
+// void CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
+//                                     Length numberOfCharacters )
+
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct SetGlyphsPerCharacterData
+{
+  std::string   description;             ///< Description of the test.
+  std::string   text;                    ///< Input text.
+  unsigned int  startIndex;              ///< The start index from where the glyphs per character table is set.
+  unsigned int  numberOfCharacters;      ///< The number of characters to set.
+  unsigned int  totalNumberOfCharacters; ///< The total number of characters.
+  unsigned int* glyphsPerCharacter;      ///< The number of glyphs per character.
+};
+
+struct SetCharacterToGlyphData
+{
+  std::string   description;             ///< Description of the test.
+  std::string   text;                    ///< Input text.
+  unsigned int  startIndex;              ///< The start index from where the character to glyph table is set.
+  unsigned int  numberOfCharacters;      ///< The number of characters to set.
+  unsigned int  totalNumberOfCharacters; ///< The total number of characters.
+  unsigned int* glyphsIndices;           ///< The glyph indices.
+};
+
+bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data )
+{
+  // 1) Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  CreateTextModel( data.text,
+                   textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  // 2) Clear the model.
+  Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+  Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+
+  if( 0u != charactersToGlyph.Count() )
+  {
+    // The number of glyphs to be removed.
+    const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex];
+
+    charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex,
+                             charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters );
+    glyphsPerCharacter.Erase( glyphsPerCharacter.Begin() + data.startIndex,
+                              glyphsPerCharacter.Begin() + data.startIndex + data.numberOfCharacters );
+
+    // Update the character to glyph indices.
+    for( Vector<GlyphIndex>::Iterator it = charactersToGlyph.Begin() + data.startIndex,
+           endIt = charactersToGlyph.End();
+         it != endIt;
+         ++it )
+    {
+      *it -= numberOfGlyphs;
+    }
+  }
+
+  // 3) Call the CreateGlyphsPerCharacterTable() function
+  visualModel->CreateGlyphsPerCharacterTable( data.startIndex,
+                                              data.numberOfCharacters );
+
+  // 4) Compare the results.
+  if( data.totalNumberOfCharacters != glyphsPerCharacter.Count() )
+  {
+    std::cout << "  Different number of characters : " << glyphsPerCharacter.Count() << ", expected : " << data.totalNumberOfCharacters << std::endl;
+    return false;
+  }
+
+  for( unsigned int i = 0u; i < data.totalNumberOfCharacters; ++i )
+  {
+    if( data.glyphsPerCharacter[i] != glyphsPerCharacter[i] )
+    {
+      std::cout << "  Different number of glyphs for index " << i << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << glyphsPerCharacter[j] << " ";
+      }
+      std::cout << std::endl;
+      std::cout << "  expected" << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << data.glyphsPerCharacter[j] << " ";
+      }
+      std::cout << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data )
+{
+  // 1) Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  CreateTextModel( data.text,
+                   textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  // 2) Clear the model.
+  Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+  Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+
+  if( 0u != charactersToGlyph.Count() )
+  {
+    // The number of glyphs to be removed.
+    const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex];
+
+    charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex,
+                             charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters );
+
+    // Update the character to glyph indices.
+    for( Vector<GlyphIndex>::Iterator it = charactersToGlyph.Begin() + data.startIndex,
+           endIt = charactersToGlyph.End();
+         it != endIt;
+         ++it )
+    {
+      *it -= numberOfGlyphs;
+    }
+  }
+
+  // 3) Call the CreateCharacterToGlyphTable() function
+  visualModel->CreateCharacterToGlyphTable( data.startIndex,
+                                            data.numberOfCharacters );
+
+  // 4) Compare the results.
+  if( data.totalNumberOfCharacters != charactersToGlyph.Count() )
+  {
+    std::cout << "  Different number of character : " << charactersToGlyph.Count() << ", expected : " << data.totalNumberOfCharacters << std::endl;
+    return false;
+  }
+
+  for( unsigned int i = 0u; i < data.totalNumberOfCharacters; ++i )
+  {
+    if( data.glyphsIndices[i] != charactersToGlyph[i] )
+    {
+      std::cout << "  Different number of character to glyph index " << i << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << charactersToGlyph[j] << " ";
+      }
+      std::cout << std::endl;
+      std::cout << "  expected" << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << data.glyphsIndices[j] << " ";
+      }
+      std::cout << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliSetGlyphsPerCharacter(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliSetGlyphsPerCharacter");
+
+  Length glyphsPerCharacter02[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+  Length glyphsPerCharacter03[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+  Length glyphsPerCharacter04[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 0u, 1u, 0u, 2u, 1u, 0u,
+                                    2u, 0u, 2u, 0u, 2u, 1u, 1u, 0u, 0u, 0u,
+                                    2u, 1u, 1u, 1u, 1u, 1u, 0u, 0u, 2u, 1u,
+                                    0u, 2u, 1u, 1u };
+
+  struct SetGlyphsPerCharacterData data[] =
+  {
+    {
+      "Zero characters text",
+      "",
+      0u,
+      0u,
+      0u,
+      NULL
+    },
+    {
+      "Simple 1 to 1 text",
+      "Hello world",
+      0u,
+      11u,
+      11u,
+      glyphsPerCharacter02,
+    },
+    {
+      "Text with different number of glyphs and characters.",
+      "Hello different world",
+      0u,
+      21u,
+      21u,
+      glyphsPerCharacter03,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update initial paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      0u,
+      22u,
+      54u,
+      glyphsPerCharacter04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update mid paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      22u,
+      14u,
+      54u,
+      glyphsPerCharacter04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update final paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      36u,
+      18u,
+      54u,
+      glyphsPerCharacter04,
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !SetGlyphsPerCharacterTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliSetCharacterToGlyph(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliSetGlyphsPerCharacter");
+
+  GlyphIndex glyphIndices02[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+  GlyphIndex glyphIndices03[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u };
+  GlyphIndex glyphIndices04[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u,
+                                  21u, 22u, 23u, 23u, 24u, 24u, 26u, 27u, 27u, 29u, 29u, 31u, 31u, 33u,
+                                  34u, 35u, 35u, 35u, 35u, 37u, 38u, 39u, 40u, 41u, 42u, 42u, 42u, 44u, 45u, 45u, 47u, 48u };
+
+  struct SetCharacterToGlyphData data[] =
+  {
+    {
+      "Zero characters text",
+      "",
+      0u,
+      0u,
+      0u,
+      NULL
+    },
+    {
+      "Simple 1 to 1 text",
+      "Hello world",
+      0u,
+      11u,
+      11u,
+      glyphIndices02,
+    },
+    {
+      "Text with different number of glyphs and characters.",
+      "Hello different world",
+      0u,
+      21u,
+      21u,
+      glyphIndices03,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update initial paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      0u,
+      22u,
+      54u,
+      glyphIndices04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update mid paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      22u,
+      14u,
+      54u,
+      glyphIndices04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update final paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      36u,
+      18u,
+      54u,
+      glyphIndices04,
+    },
+  };
+
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !SetCharacterToGlyphTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
index 10f910c..6786bc5 100644 (file)
@@ -214,30 +214,30 @@ void CreateTextModel( const std::string& text,
   Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
   Vector<GlyphIndex> newParagraphGlyphs;
 
-  const Length currentNumberOfGlyphs = glyphs.Count();
   const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
 
   ShapeText( textToShape,
              lineBreakInfo,
              scripts,
              validFonts,
+             0u,
+             0u,
+             numberOfCharacters,
              glyphs,
              glyphsToCharactersMap,
              charactersPerGlyph,
              newParagraphGlyphs );
 
   // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-  visualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
-  visualModel->CreateCharacterToGlyphTable( numberOfCharacters );
+  visualModel->CreateGlyphsPerCharacterTable( 0u, numberOfCharacters );
+  visualModel->CreateCharacterToGlyphTable( 0u, numberOfCharacters );
 
-  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
+  const Length numberOfGlyphs = glyphs.Count();
 
   // 8) Get the glyph metrics
   MetricsPtr metrics = Metrics::New( fontClient );
 
-  const GlyphIndex glyphIndex = currentNumberOfGlyphs;
-
-  GlyphInfo* glyphsBuffer = glyphs.Begin() + glyphIndex;
+  GlyphInfo* glyphsBuffer = glyphs.Begin();
   metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
 
   // Update the width and advance of all new paragraph characters.
@@ -247,7 +247,7 @@ void CreateTextModel( const std::string& text,
        ++it )
   {
     const GlyphIndex index = *it;
-    GlyphInfo& glyph = *( glyphsBuffer + ( index - glyphIndex ) );
+    GlyphInfo& glyph = *( glyphsBuffer + index );
 
     glyph.xBearing = 0.f;
     glyph.width = 0.f;
index 5061193..5313d0c 100644 (file)
@@ -40,13 +40,14 @@ void ShapeText( const Vector<Character>& text,
                 const Vector<LineBreakInfo>& lineBreakInfo,
                 const Vector<ScriptRun>& scripts,
                 const Vector<FontRun>& fonts,
+                CharacterIndex startCharacterIndex,
+                GlyphIndex startGlyphIndex,
+                Length numberOfCharacters,
                 Vector<GlyphInfo>& glyphs,
                 Vector<CharacterIndex>& glyphToCharacterMap,
                 Vector<Length>& charactersPerGlyph,
                 Vector<GlyphIndex>& newParagraphGlyphs )
 {
-  const Length numberOfCharacters = text.Count();
-
   if( 0u == numberOfCharacters )
   {
     // Nothing to do if there are no characters.
@@ -56,14 +57,15 @@ void ShapeText( const Vector<Character>& text,
 #ifdef DEBUG_ENABLED
   const Length numberOfFontRuns = fonts.Count();
   const Length numberOfScriptRuns = scripts.Count();
+  const Length totalNumberOfCharacters = text.Count();
 #endif
 
   DALI_ASSERT_DEBUG( ( 0u != numberOfFontRuns ) &&
-                     ( numberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) &&
+                     ( totalNumberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) &&
                      "Toolkit::Text::ShapeText. All characters must have a font set." );
 
   DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) &&
-                     ( numberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) &&
+                     ( totalNumberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) &&
                      "Toolkit::Text::ShapeText. All characters must have a script set." );
 
   // The text needs to be split in chunks of consecutive characters.
@@ -73,8 +75,30 @@ void ShapeText( const Vector<Character>& text,
   TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get();
 
   // To shape the text a font and an script is needed.
+
+  // Get the font run containing the startCharacterIndex character.
   Vector<FontRun>::ConstIterator fontRunIt = fonts.Begin();
+  for( Vector<FontRun>::ConstIterator endIt = fonts.End(); fontRunIt < endIt; ++fontRunIt )
+  {
+    const FontRun& run = *fontRunIt;
+    if( startCharacterIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+    {
+      // Found.
+      break;
+    }
+  }
+
+  // Get the script run containing the startCharacterIndex character.
   Vector<ScriptRun>::ConstIterator scriptRunIt = scripts.Begin();
+  for( Vector<ScriptRun>::ConstIterator endIt = scripts.End(); scriptRunIt < endIt; ++scriptRunIt )
+  {
+    const ScriptRun& run = *scriptRunIt;
+    if( startCharacterIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+    {
+      // Found.
+      break;
+    }
+  }
 
   // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped.
   CharacterIndex previousIndex = 0u;
@@ -87,20 +111,25 @@ void ShapeText( const Vector<Character>& text,
   // There is no way to know the number of glyphs before shaping the text.
   // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters.
 
-  Length numberOfGlyphsReserved = static_cast<Length>( numberOfCharacters * 1.3f );
-  glyphs.Resize( numberOfGlyphsReserved );
-  glyphToCharacterMap.Resize( numberOfGlyphsReserved );
+  const Length currentNumberOfGlyphs = glyphs.Count();
+  const Length numberOfGlyphsReserved = static_cast<Length>( numberOfCharacters * 1.3f );
+  glyphs.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved );
+  glyphToCharacterMap.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved );
 
   // The actual number of glyphs.
-  Length totalNumberOfGlyphs = 0u;
+  Length totalNumberOfGlyphs = currentNumberOfGlyphs;
+  // The number of new glyphs.
+  Length numberOfNewGlyphs = 0u;
 
   const Character* const textBuffer = text.Begin();
   const LineBreakInfo* const lineBreakInfoBuffer = lineBreakInfo.Begin();
-  GlyphInfo* glyphsBuffer = glyphs.Begin();
   CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
+  Length glyphIndex = startGlyphIndex;
+
   // Traverse the characters and shape the text.
-  for( previousIndex = 0; previousIndex < numberOfCharacters; )
+  const CharacterIndex lastCharacter = startCharacterIndex + numberOfCharacters;
+  for( previousIndex = startCharacterIndex; previousIndex < lastCharacter; )
   {
     // Get the font id and the script.
     const FontRun& fontRun = *fontRunIt;
@@ -138,40 +167,41 @@ void ShapeText( const Vector<Character>& text,
                                                  currentFontId,
                                                  currentScript );
 
-    const Length glyphIndex = totalNumberOfGlyphs;
-    totalNumberOfGlyphs += numberOfGlyphs;
-
-    if( totalNumberOfGlyphs > numberOfGlyphsReserved )
+    // Retrieve the glyphs and the glyph to character conversion map.
+    Vector<GlyphInfo> tmpGlyphs;
+    Vector<CharacterIndex> tmpGlyphToCharacterMap;
+    tmpGlyphs.Resize( numberOfGlyphs );
+    tmpGlyphToCharacterMap.Resize( numberOfGlyphs );
+    shaping.GetGlyphs( tmpGlyphs.Begin(),
+                       tmpGlyphToCharacterMap.Begin() );
+
+    // Update the indices.
+    if( 0u != totalNumberOfGlyphs )
     {
-      // Resize the vectors to get enough space.
-      numberOfGlyphsReserved = static_cast<Length>( totalNumberOfGlyphs * 1.3f );
-      glyphs.Resize( numberOfGlyphsReserved );
-      glyphToCharacterMap.Resize( numberOfGlyphsReserved );
-
-      // Iterators are not valid anymore, set them again.
-      glyphsBuffer = glyphs.Begin();
-      glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+      for( Vector<CharacterIndex>::Iterator it = tmpGlyphToCharacterMap.Begin(),
+             endIt = tmpGlyphToCharacterMap.End();
+           it != endIt;
+           ++it )
+      {
+        *it += previousIndex;
+      }
     }
 
-    // Retrieve the glyphs and the glyph to character conversion map.
-    shaping.GetGlyphs( glyphsBuffer + glyphIndex,
-                       glyphToCharacterMapBuffer + glyphIndex );
+    totalNumberOfGlyphs += numberOfGlyphs;
+    numberOfNewGlyphs += numberOfGlyphs;
+
+    glyphs.Insert( glyphs.Begin() + glyphIndex, tmpGlyphs.Begin(), tmpGlyphs.End() );
+    glyphToCharacterMap.Insert( glyphToCharacterMap.Begin() + glyphIndex, tmpGlyphToCharacterMap.Begin(), tmpGlyphToCharacterMap.End() );
+    glyphIndex += numberOfGlyphs;
+
+    // Set the buffer pointers again.
+    glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
     if( isNewParagraph )
     {
       // Add the index of the new paragraph glyph to a vector.
       // Their metrics will be updated in a following step.
-      newParagraphGlyphs.PushBack( totalNumberOfGlyphs - 1u );
-    }
-
-    // Update indices.
-    if( 0u != glyphIndex )
-    {
-      for( Length index = glyphIndex; index < glyphIndex + numberOfGlyphs; ++index )
-      {
-        CharacterIndex& characterIndex = *( glyphToCharacterMapBuffer + index );
-        characterIndex += previousIndex;
-      }
+      newParagraphGlyphs.PushBack( glyphIndex - 1u );
     }
 
     // Update the iterators to get the next font or script run.
@@ -188,19 +218,28 @@ void ShapeText( const Vector<Character>& text,
     previousIndex = currentIndex;
   }
 
+  // Update indices.
+  for( Length index = startGlyphIndex + numberOfNewGlyphs; index < totalNumberOfGlyphs; ++index )
+  {
+    CharacterIndex& characterIndex = *( glyphToCharacterMapBuffer + index );
+    characterIndex += numberOfCharacters;
+  }
+
   // Add the number of characters per glyph.
   charactersPerGlyph.Reserve( totalNumberOfGlyphs );
-  previousIndex = 0u;
-  for( Length index = 1u; index < totalNumberOfGlyphs; ++index )
+  Length* charactersPerGlyphBuffer = charactersPerGlyph.Begin();
+
+  const GlyphIndex lastGlyph = startGlyphIndex + numberOfNewGlyphs;
+  previousIndex = startCharacterIndex;
+  for( Length index = startGlyphIndex + 1u; index < lastGlyph; ++index )
   {
     const CharacterIndex characterIndex = *( glyphToCharacterMapBuffer + index );
 
-    charactersPerGlyph.PushBack( characterIndex - previousIndex );
+    charactersPerGlyph.Insert( charactersPerGlyphBuffer + index - 1u, characterIndex - previousIndex );
 
     previousIndex = characterIndex;
   }
-
-  charactersPerGlyph.PushBack( numberOfCharacters - previousIndex );
+  charactersPerGlyph.Insert( charactersPerGlyphBuffer + lastGlyph - 1u, numberOfCharacters + startCharacterIndex - previousIndex );
 
   // Resize the vectors to set the right number of items.
   glyphs.Resize( totalNumberOfGlyphs );
index 70e2e58..2cd47cb 100644 (file)
@@ -44,6 +44,9 @@ class VisualModel;
  * @param[in] lineBreakInfo The line break info.
  * @param[in] scripts Vector containing the script runs for the whole text.
  * @param[in] fonts Vector with validated fonts.
+ * @param[in] startCharacterIndex The character from where the text is shaped.
+ * @param[in] startGlyphIndex The glyph from where the text is shaped.
+ * @param[in] numberOfCharacters The number of characters to be shaped.
  * @param[out] glyphs Vector of glyphs in the visual order.
  * @param[out] glyphToCharacterMap Vector containing the first character in the logical model that each glyph relates to.
  * @param[out] charactersPerGlyph Vector containing the number of characters per glyph.
@@ -53,6 +56,9 @@ void ShapeText( const Vector<Character>& text,
                 const Vector<LineBreakInfo>& lineBreakInfo,
                 const Vector<ScriptRun>& scripts,
                 const Vector<FontRun>& fonts,
+                CharacterIndex startCharacterIndex,
+                GlyphIndex startGlyphIndex,
+                Length numberOfCharacters,
                 Vector<GlyphInfo>& glyphs,
                 Vector<CharacterIndex>& glyphToCharacterMap,
                 Vector<Length>& charactersPerGlyph,
index 9458933..c2c2fa8 100644 (file)
@@ -453,6 +453,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
   Vector<GlyphIndex> newParagraphGlyphs;
   newParagraphGlyphs.Reserve( numberOfParagraphs );
 
+  GlyphIndex startGlyphIndex = 0u;
   if( SHAPE_TEXT & operations )
   {
     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
@@ -461,21 +462,24 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                lineBreakInfo,
                scripts,
                validFonts,
+               startIndex,
+               startGlyphIndex,
+               requestedNumberOfCharacters,
                glyphs,
                glyphsToCharactersMap,
                charactersPerGlyph,
                newParagraphGlyphs );
 
     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-    mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
-    mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
+    mVisualModel->CreateGlyphsPerCharacterTable( startIndex, numberOfCharacters );
+    mVisualModel->CreateCharacterToGlyphTable( startIndex, numberOfCharacters );
   }
 
   const Length numberOfGlyphs = glyphs.Count();
 
   if( GET_GLYPH_METRICS & operations )
   {
-    GlyphInfo* glyphsBuffer = glyphs.Begin();
+    GlyphInfo* glyphsBuffer = glyphs.Begin() + startGlyphIndex;
     mMetrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
 
     // Update the width and advance of all new paragraph characters.
index 561beee..3e9c123 100644 (file)
@@ -35,29 +35,50 @@ VisualModelPtr VisualModel::New()
   return VisualModelPtr( new VisualModel() );
 }
 
-void VisualModel::CreateCharacterToGlyphTable( Length numberOfCharacters )
+void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex,
+                                               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;
   }
-  mCharactersToGlyph.Reserve( numberOfCharacters );
 
-  DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u ||
-                     ( 0u == numberOfCharacters ) );
+  DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u );
+
+  // 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<GlyphIndex> newCharactersToGlyph;
+  GlyphIndex* charactersToGlyphBuffer = NULL;
+
+  // 1) Reserve some space for the glyph indices to avoid reallocations.
+  if( updateCurrentBuffer )
+  {
+    newCharactersToGlyph.Resize( numberOfCharacters );
+    charactersToGlyphBuffer = newCharactersToGlyph.Begin();
+  }
+  else
+  {
+    mCharactersToGlyph.Resize( numberOfCharacters );
+    charactersToGlyphBuffer = mCharactersToGlyph.Begin() + startIndex;
+  }
 
   const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin();
 
   // 2) Traverse the glyphs and set the glyph indices per character.
 
   // Index to the glyph.
-  GlyphIndex glyphIndex = 0u;
-  CharacterIndex characterIndex = 0u;
-  for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin(),
+  const GlyphIndex startGlyphIndex = updateCurrentBuffer ? *( mCharactersToGlyph.Begin() + startIndex ) : 0u;
+  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 != endIt ) && ( characterIndex < lastCharacterIndexPlusOne );
        ++it )
   {
     const Length numberOfCharactersPerGlyph = *it;
@@ -66,34 +87,79 @@ void VisualModel::CreateCharacterToGlyphTable( Length numberOfCharacters )
     // Set the glyph indices.
     for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex )
     {
-      mCharactersToGlyph.PushBack( glyphIndex );
+      *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 )
+    {
+      *it += numberOfGlyphs;
+    }
+
+    mCharactersToGlyph.Insert( mCharactersToGlyph.Begin() + startIndex,
+                               newCharactersToGlyph.Begin(),
+                               newCharactersToGlyph.End() );
+
+  }
 }
 
-void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters )
+void VisualModel::CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
+                                                 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;
   }
-  mGlyphsPerCharacter.Reserve( numberOfCharacters );
 
   // 2) Traverse the glyphs and set the number of glyphs per character.
 
+  // The glyph index.
+  const GlyphIndex glyphIndex = updateCurrentBuffer  ? *( mCharactersToGlyph.Begin() + startIndex ) : 0u;
+  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() + glyphIndex,
          endIt = mCharactersPerGlyph.End();
-       it != endIt;
+       ( it != endIt ) && ( traversedCharacters < numberOfCharacters );
        ++it )
   {
     const Length numberOfCharactersPerGlyph = *it;
+    traversedCharacters += numberOfCharactersPerGlyph;
 
     // Set the glyphs per character.
     if( 0u == numberOfCharactersPerGlyph )
@@ -103,16 +169,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;
     }
   }
+
+  // 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,
index ca579e1..eb2e5a0 100644 (file)
@@ -66,16 +66,20 @@ public:
    *
    * @pre The glyphs per character table needs to be created first.
    *
+   * @param[in] startIndex The character from where the conversion table is created.
    * @param[in] numberOfCharacters The number of characters.
    */
-  void CreateCharacterToGlyphTable( Length numberOfCharacters = 0u );
+  void CreateCharacterToGlyphTable( CharacterIndex startIndex,
+                                    Length numberOfCharacters );
 
   /**
    * @brief Creates an array containing the number of glyphs per character.
    *
+   * @param[in] startIndex The character from where the table is created.
    * @param[in] numberOfCharacters The number of characters.
    */
-  void CreateGlyphsPerCharacterTable( Length numberOfCharacters = 0u );
+  void CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
+                                      Length numberOfCharacters );
 
   /**
    * @brief Retrieves glyphs in the given buffer.