TextModel - Create the bidirectional info for a given range of characters inside... 56/60856/5
authorVictor Cebollada <v.cebollada@samsung.com>
Thu, 18 Feb 2016 09:45:31 +0000 (09:45 +0000)
committerVictor Cebollada <v.cebollada@samsung.com>
Wed, 2 Mar 2016 14:48:11 +0000 (14:48 +0000)
Change-Id: I00d0c68d9d354d30e6fe3ad67de8d99f7c0651d4
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
12 files changed:
automated-tests/src/dali-toolkit-internal/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/utc-Dali-BidirectionalSupport.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.h [new file with mode: 0644]
dali-toolkit/internal/text/bidirectional-support.cpp
dali-toolkit/internal/text/bidirectional-support.h
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-definitions.h

index 1ce796d..7e21216 100644 (file)
@@ -11,6 +11,8 @@ SET(TC_SOURCES
  utc-Dali-Text-CharacterSetConversion.cpp
  utc-Dali-Text-Segmentation.cpp
  utc-Dali-Text-MultiLanguage.cpp
+ utc-Dali-LogicalModel.cpp
+ utc-Dali-BidirectionalSupport.cpp
 )
 
 # Append list of test harness files (Won't get parsed for test cases)
@@ -26,6 +28,7 @@ LIST(APPEND TC_SOURCES
    ../dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.cpp
    ../dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp
    ../dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
    ../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-application.cpp
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-BidirectionalSupport.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-BidirectionalSupport.cpp
new file mode 100644 (file)
index 0000000..92ee580
--- /dev/null
@@ -0,0 +1,945 @@
+/*
+ * 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/devel-api/text-abstraction/bidirectional-support.h>
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/text-run-container.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 SetBidirectionalInfo( const Vector<Character>& text,
+//                            const Vector<ScriptRun>& scripts,
+//                            const Vector<LineBreakInfo>& lineBreakInfo,
+//                            CharacterIndex startIndex,
+//                            Length numberOfCharacters,
+//                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
+// void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+//                    CharacterIndex startIndex,
+//                    Length numberOfCharacters,
+//                    Vector<LineRun>& lineRuns,
+//                    Vector<BidirectionalLineInfoRun>& lineInfoRuns )
+// bool GetMirroredText( const Vector<Character>& text,
+//                       Vector<CharacterDirection>& directions,
+//                       const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+//                       CharacterIndex startIndex,
+//                       Length numberOfCharacters,
+//                       Vector<Character>& mirroredText )
+// void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+//                              CharacterIndex startIndex,
+//                              Length numberOfCharacters,
+//                              Vector<CharacterDirection>& directions )
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct SetBidirectionalInfoData
+{
+  std::string   description;                 ///< Description of the test.
+  std::string   text;                        ///< Input text.
+  unsigned int  startIndex;                  ///< The index from where the model is updated.
+  unsigned int  numberOfCharacters;          ///< The number of characters to update.
+  unsigned int  numberOfParagraphs;          ///< The expected number of bidirectional paragraphs.
+  unsigned int* indices;                     ///< The expected indices to the first character of each paragraph.
+  unsigned int* numberOfParagraphCharacters; ///< The expected number of characters of each paragraph.
+  bool*         directions;                  ///< The expected direction of each paragraph.
+};
+
+struct BidiLineData
+{
+  unsigned int  characterIndex;
+  unsigned int  numberOfCharacters;
+  unsigned int* visualToLogical;
+};
+
+struct ReorderLinesData
+{
+  std::string   description;        ///< Description of the test.
+  std::string   text;               ///< Input text.
+  unsigned int  startIndex;         ///< The index from where the model is updated.
+  unsigned int  numberOfCharacters; ///< The number of characters.
+  unsigned int  numberOfLineInfo;   ///< The number or reordered lines.
+  BidiLineData* bidiLineData;       ///< The bidirectional line info.
+};
+
+struct GetMirroredTextData
+{
+  std::string  description;        ///< Description of the test.
+  std::string  text;               ///< Input text.
+  unsigned int startIndex;         ///< The index from where the model is updated.
+  unsigned int numberOfCharacters; ///< The number of the characters.
+  std::string  mirroredText;       ///< The expected result.
+};
+
+struct GetCharactersDirectionData
+{
+  std::string  description;         ///< Description of the test.
+  std::string  text;                ///< Input text.
+  unsigned int startIndex;          ///< The index from where the model is updated.
+  unsigned int numberOfCharacters;  ///< The number of characters.
+  bool*        directions;          ///< The expected directions.
+};
+
+bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
+{
+  // 1) Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  // Create the model.
+  CreateTextModel( data.text,
+                   textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  // 2) Clear the bidirectional paragraph info data.
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+  if( 0u != data.numberOfCharacters )
+  {
+    ClearCharacterRuns( data.startIndex,
+                        data.startIndex + data.numberOfCharacters - 1u,
+                        bidirectionalInfo );
+  }
+
+  // 3) Call the SetBidirectionalInfo() function.
+  SetBidirectionalInfo( logicalModel->mText,
+                        logicalModel->mScriptRuns,
+                        logicalModel->mLineBreakInfo,
+                        data.startIndex,
+                        data.numberOfCharacters,
+                        bidirectionalInfo );
+
+  // 4) Compare with the expected results.
+  TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+  if( data.numberOfParagraphs != bidirectionalInfo.Count() )
+  {
+    // Different number of expected bidirectional paragraphs.
+    std::cout << "  Different number of bidi paragraphs : " << bidirectionalInfo.Count() << ", expected : " << data.numberOfParagraphs << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.numberOfParagraphs; ++index )
+  {
+    const BidirectionalParagraphInfoRun& run = bidirectionalInfo[index];
+
+    const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( run.bidirectionalInfoIndex );
+    if( direction != data.directions[index] )
+    {
+      std::cout << "  Different direction" << std::endl;
+      std::cout << "        paragraph : " << index << std::endl;
+      std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+      std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+      return false;
+    }
+
+    if( run.characterRun.characterIndex != data.indices[index] )
+    {
+      std::cout << "  Different index" << std::endl;
+      std::cout << "        paragraph : " << index << std::endl;
+      std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+      std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+      return false;
+    }
+    if( run.characterRun.numberOfCharacters != data.numberOfParagraphCharacters[index] )
+    {
+      std::cout << "  Different number of characters" << std::endl;
+      std::cout << "        paragraph : " << index << std::endl;
+      std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+      std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * @brief Frees previously allocated bidirectional resources.
+ *
+ * @param[in] bidirectionalLineInfo Bidirectional info per line.
+ * @param[in] startIndex Index to the first line with bidirectional info to be freed.
+ * @param[in] endIndex Index to the last line with bidirectional info to be freed.
+ */
+void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
+                                         uint32_t startIndex,
+                                         uint32_t endIndex )
+{
+  // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+  for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + startIndex,
+         endIt = bidirectionalLineInfo.Begin() + endIndex;
+       it != endIt;
+       ++it )
+  {
+    BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+    free( bidiLineInfo.visualToLogicalMap );
+  }
+}
+
+bool ReorderLinesTest( const ReorderLinesData& data )
+{
+  // 1) Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size textArea(100.f, 300.f);
+  Size layoutSize;
+
+  // Create the model.
+  CreateTextModel( data.text,
+                   textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  // 2) Clear the bidirectional line info data.
+  uint32_t startRemoveIndex = logicalModel->mBidirectionalLineInfo.Count();
+  uint32_t endRemoveIndex = startRemoveIndex;
+  ClearCharacterRuns( data.startIndex,
+                      data.startIndex + data.numberOfCharacters - 1u,
+                      logicalModel->mBidirectionalLineInfo,
+                      startRemoveIndex,
+                      endRemoveIndex );
+
+  // Index to the first index to be removed.
+
+  FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, startRemoveIndex, endRemoveIndex );
+  BidirectionalLineInfoRun* bidiLineBuffer = logicalModel->mBidirectionalLineInfo.Begin();
+  logicalModel->mBidirectionalLineInfo.Erase( bidiLineBuffer + startRemoveIndex,
+                                              bidiLineBuffer + endRemoveIndex );
+
+  // 3) Call the function ReorderLines()
+
+  ReorderLines( logicalModel->mBidirectionalParagraphInfo,
+                data.startIndex,
+                data.numberOfCharacters,
+                visualModel->mLines,
+                logicalModel->mBidirectionalLineInfo );
+
+  // 4) Compare the results.
+
+  if( data.numberOfLineInfo != logicalModel->mBidirectionalLineInfo.Count() )
+  {
+    // Different number of bidirectional lines.
+    std::cout << "  different number of bidi lines : " << logicalModel->mBidirectionalLineInfo.Count() << ", expected : " << data.numberOfLineInfo << std::endl;
+    for( unsigned int index = 0u; index < logicalModel->mBidirectionalLineInfo.Count(); ++index )
+    {
+      const BidirectionalLineInfoRun& run = logicalModel->mBidirectionalLineInfo[index];
+      const BidiLineData& bidiLineData = data.bidiLineData[index];
+
+      std::cout << "  bidi line : " << index << ", index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << std::endl;
+      std::cout << "                      expected index : " << bidiLineData.characterIndex << ", num chars : " << bidiLineData.numberOfCharacters << std::endl;
+    }
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.numberOfLineInfo; ++index )
+  {
+    const BidirectionalLineInfoRun& run = logicalModel->mBidirectionalLineInfo[index];
+    const BidiLineData& bidiLineData = data.bidiLineData[index];
+
+    if( bidiLineData.characterIndex != run.characterRun.characterIndex )
+    {
+      std::cout << "  bidi line : " << index << ", index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << std::endl;
+      std::cout << "                      expected index : " << bidiLineData.characterIndex << ", num chars : " << bidiLineData.numberOfCharacters << std::endl;
+      return false;
+    }
+    if( bidiLineData.numberOfCharacters != run.characterRun.numberOfCharacters )
+    {
+      std::cout << "  bidi line : " << index << ", index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << std::endl;
+      std::cout << "                      expected index : " << bidiLineData.characterIndex << ", num chars : " << bidiLineData.numberOfCharacters << std::endl;
+      return false;
+    }
+
+    for( unsigned int i = 0u; i < run.characterRun.numberOfCharacters; ++i )
+    {
+      if( bidiLineData.visualToLogical[i] != run.visualToLogicalMap[i] )
+      {
+        std::cout << "           v2l : ";
+        for( unsigned int i = 0u; i < run.characterRun.numberOfCharacters; ++i )
+        {
+          std::cout << run.visualToLogicalMap[i] << " ";
+        }
+        std::cout << std::endl;
+        std::cout << "  expected v2l : ";
+        for( unsigned int i = 0u; i < run.characterRun.numberOfCharacters; ++i )
+        {
+          std::cout << bidiLineData.visualToLogical[i] << " ";
+        }
+        std::cout << std::endl;
+
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool GetMirroredTextTest( const GetMirroredTextData& data )
+{
+  // 1) Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  // Create the model.
+  CreateTextModel( data.text,
+                   textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  // 2) Call the GetMirroredText() function for the whole text
+  Vector<Character> mirroredText;
+  bool mirrored = false;
+  mirrored = GetMirroredText( logicalModel->mText,
+                              logicalModel->mCharacterDirections,
+                              logicalModel->mBidirectionalParagraphInfo,
+                              0u,
+                              logicalModel->mText.Count(),
+                              mirroredText );
+
+  // 3) Call the GetMirroredText() function for the given index + number of characters
+  mirrored = GetMirroredText( logicalModel->mText,
+                              logicalModel->mCharacterDirections,
+                              logicalModel->mBidirectionalParagraphInfo,
+                              data.startIndex,
+                              data.numberOfCharacters,
+                              mirroredText );
+
+  // 4) Compare the results.
+
+  // Convert to utf8
+  std::string mirroredString;
+  Utf32ToUtf8( mirroredText.Begin(),
+               mirroredText.Count(),
+               mirroredString );
+
+  if( !mirrored && ( mirroredString != data.text ) )
+  {
+    std::cout << "  No mirrored text and mirroredString != data.text." << std::endl;
+    std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
+    std::cout << "             text : [" << data.text << "]" << std::endl;
+    return false;
+  }
+
+  if( mirrored && ( mirroredString == data.text ) )
+  {
+    std::cout << "  Mirrored text and mirroredString == data.text." << std::endl;
+    std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
+    std::cout << "             text : [" << data.text << "]" << std::endl;
+    return false;
+  }
+
+  if( mirrored && ( mirroredString != data.mirroredText ) )
+  {
+    std::cout << "  Mirrored text and mirroredString != data.mirroredText." << std::endl;
+    std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
+    std::cout << "             text : [" << data.mirroredText << "]" << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
+{
+  // 1) Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  // Create the model.
+  CreateTextModel( data.text,
+                   textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+
+  // 2) Clear the direction info data.
+  Vector<CharacterDirection>& directions = logicalModel->mCharacterDirections;
+
+  directions.Erase( directions.Begin() + data.startIndex,
+                    directions.Begin() + data.startIndex + data.numberOfCharacters );
+
+  // 3) Call GetCharactersDirection() function.
+
+  GetCharactersDirection( bidirectionalInfo,
+                          logicalModel->mText.Count(),
+                          data.startIndex,
+                          data.numberOfCharacters,
+                          directions );
+
+  for( unsigned int index = 0u; index < logicalModel->mText.Count(); ++index )
+  {
+    if( data.directions[index] != directions[index] )
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliSetBidirectionalInfo(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliSetBidirectionalInfo");
+
+  unsigned int indices01[] = {};
+  unsigned int numberOfCharacters01[] = {};
+  bool         direction01[] = {};
+  unsigned int indices02[] = {};
+  unsigned int numberOfCharacters02[] = {};
+  bool         direction02[] = {};
+  unsigned int indices03[] = { 17u, 48u };
+  unsigned int numberOfCharacters03[] = { 14u, 14u };
+  bool         direction03[] = { true, true };
+  unsigned int indices04[] = { 17u, 31u, 79u };
+  unsigned int numberOfCharacters04[] = { 14u, 48u, 31u };
+  bool         direction04[] = { true, false, true };
+  unsigned int indices05[] = { 17u, 41u, 117u };
+  unsigned int numberOfCharacters05[] = { 24u, 76u, 49u };
+  bool         direction05[] = { true, false, true };
+  unsigned int indices06[] = { 17u, 48u };
+  unsigned int numberOfCharacters06[] = { 14u, 14u };
+  bool         direction06[] = { true, true };
+  unsigned int indices07[] = { 17u, 31u, 79u };
+  unsigned int numberOfCharacters07[] = { 14u, 48u, 31u };
+  bool         direction07[] = { true, false, true };
+  unsigned int indices08[] = { 17u, 41u, 117u };
+  unsigned int numberOfCharacters08[] = { 24u, 76u, 49u };
+  bool         direction08[] = { true, false, true };
+
+  struct SetBidirectionalInfoData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      0u,
+      indices01,
+      numberOfCharacters01,
+      direction01
+    },
+    {
+      "Some left to right paragraphs",
+      "Hello world\ndemo\n\n",
+      0u,
+      18u,
+      0u,
+      indices02,
+      numberOfCharacters02,
+      direction02
+    },
+    {
+      "A mix of left to right and right to left paragraphs.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
+      0u,
+      78u,
+      2u,
+      indices03,
+      numberOfCharacters03,
+      direction03
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
+      0u,
+      126u,
+      3u,
+      indices04,
+      numberOfCharacters04,
+      direction04
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts.",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      0u,
+      182u,
+      3u,
+      indices05,
+      numberOfCharacters05,
+      direction05
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Updates a left to right paragraph.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
+      31u,
+      17u,
+      2u,
+      indices06,
+      numberOfCharacters06,
+      direction06
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
+      0u,
+      126u,
+      3u,
+      indices07,
+      numberOfCharacters07,
+      direction07
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates initial paragraphs.",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      0u,
+      41u,
+      3u,
+      indices08,
+      numberOfCharacters08,
+      direction08
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates mid paragraphs.",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      41u,
+      76u,
+      3u,
+      indices08,
+      numberOfCharacters08,
+      direction08
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates from character 85",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      117u,
+      65u,
+      3u,
+      indices08,
+      numberOfCharacters08,
+      direction08
+    },
+  };
+  const unsigned int numberOfTests = 10u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !SetBidirectionalInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliReorderLines(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliSetBidirectionalInfo");
+
+  unsigned int visualToLogical0301[] = { 0u, 1u, 2u, 3u, 4u, 5u, 9u, 8u, 7u, 6u, 10u };
+  unsigned int visualToLogical0302[] = { 3u, 2u, 1u, 0u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+  unsigned int visualToLogical0303[] = { 0u, 1u, 2u, 3u, 4u };
+  unsigned int visualToLogical0304[] = { 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0305[] = { 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0306[] = { 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0307[] = { 13u, 8u, 9u, 10u, 11u, 12u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0308[] = { 5u, 0u, 1u, 2u, 3u, 4u };
+  unsigned int visualToLogical0309[] = { 0u, 1u, 2u, 3u, 4u, 5u, 9u, 8u, 7u, 6u, 10u };
+  unsigned int visualToLogical0310[] = { 3u, 2u, 1u, 0u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+  unsigned int visualToLogical0311[] = { 0u, 1u, 2u, 3u, 4u };
+  unsigned int visualToLogical0312[] = { 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0313[] = { 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0314[] = { 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0315[] = { 13u, 8u, 9u, 10u, 11u, 12u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int visualToLogical0316[] = { 0u, 1u, 2u, 3u, 4u };
+
+  BidiLineData bidiLine01[] = {};
+  BidiLineData bidiLine02[] = {};
+  BidiLineData bidiLine03[] = {
+    {
+      17u,
+      11u,
+      visualToLogical0301
+    },
+    {
+      28u,
+      11u,
+      visualToLogical0302
+    },
+    {
+      39u,
+      5u,
+      visualToLogical0303
+    },
+    {
+      44u,
+      13u,
+      visualToLogical0304
+    },
+    {
+      57u,
+      11u,
+      visualToLogical0305
+    },
+    {
+      68u,
+      10u,
+      visualToLogical0306
+    },
+    {
+      78u,
+      14u,
+      visualToLogical0307
+    },
+    {
+      92u,
+      6u,
+      visualToLogical0308
+    },
+    {
+      115u,
+      11u,
+      visualToLogical0309
+    },
+    {
+      126u,
+      11u,
+      visualToLogical0310
+    },
+    {
+      137u,
+      5u,
+      visualToLogical0311
+    },
+    {
+      142u,
+      13u,
+      visualToLogical0312
+    },
+    {
+      155u,
+      11u,
+      visualToLogical0313
+    },
+    {
+      166u,
+      10u,
+      visualToLogical0314
+    },
+    {
+      176u,
+      14u,
+      visualToLogical0315
+    },
+    {
+      190u,
+      5u,
+      visualToLogical0316
+    },
+  };
+
+  struct ReorderLinesData data[] =
+  {
+    {
+      "Zero characters.",
+      "",
+      0u,
+      0u,
+      0u,
+      bidiLine01
+    },
+    {
+      "Left to right text only.",
+      "Hello world demo\nhello world demo\nhello world demo.",
+      0u,
+      51u,
+      0u,
+      bidiLine02
+    },
+    {
+      "Bidirectional paragraphs.",
+      "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+      0u,
+      195u,
+      16u,
+      bidiLine03
+    },
+    {
+      "Bidirectional paragraphs. Update initial paragraphs.",
+      "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+      0u,
+      44u,
+      16u,
+      bidiLine03
+    },
+    {
+      "Bidirectional paragraphs. Update middle paragraphs.",
+      "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+      44u,
+      54u,
+      16u,
+      bidiLine03
+    },
+    {
+      "Bidirectional paragraphs. Update final paragraphs.",
+      "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+      142u,
+      53u,
+      16u,
+      bidiLine03
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !ReorderLinesTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetMirroredText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliGetMirroredText");
+
+  struct GetMirroredTextData data[] =
+  {
+    {
+      "Zero characters.",
+      "",
+      0u,
+      0u,
+      ""
+    },
+    {
+      "Left to right characters only.",
+      "Hello world\nhello world demo.",
+      0u,
+      29u,
+      "Hello world\nhello world demo."
+    },
+    {
+      "Right to left characters but with no characters to mirror.",
+      "שלום עולם\nمرحبا بالعالم",
+      0u,
+      23u,
+      "שלום עולם\nمرحبا بالعالم"
+    },
+    {
+      "Right to left characters with some characters to mirror.",
+      "שלום עולם\n(مرحبا بالعالم)",
+      0u,
+      25u,
+      "שלום עולם\n)مرحبا بالعالم("
+    },
+    {
+      "Right to left characters with some characters to mirror. Update last paragraph.",
+      "שלום עולם\n(مرحبا بالعالم)",
+      10u,
+      15u,
+      "שלום עולם\n)مرحبا بالعالم("
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs.",
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+      0u,
+      239u,
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום )hello) world demo )עולם(\nשלום )مرحبا بالعالم עולם( )hello("
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update middle paragraphs.",
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+      29u,
+      38u,
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update middle paragraphs (2).",
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+      67u,
+      100u,
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
+    },
+  };
+  const unsigned int numberOfTests = 8u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !GetMirroredTextTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetCharactersDirection(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliGetCharactersDirection");
+
+  bool directions01[] = {};
+  bool directions02[] = {
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false };
+  bool directions03[] = {
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true };
+  bool directions04[] = {
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  false, false, false, false, false, false,
+    false, false, false, false, false };
+  bool directions05[] = {
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  false, true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
+    false, false, false, false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
+    false, false, false, false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  false, false, false, false, false };
+
+  struct GetCharactersDirectionData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      directions01
+    },
+    {
+      "Left to right characters only",
+      "Hello world\nhello world demo",
+      0u,
+      28u,
+      directions02
+    },
+    {
+      "Right to left characters only",
+      "שלום עולם\nשלום עולם",
+      0u,
+      19u,
+      directions03
+    },
+    {
+      "Mix of bidirectional text",
+      "Hello world\nhello world שלום עולם\nשלום עולם hello world",
+      0u,
+      55u,
+      directions04
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs.",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      0u,
+      227u,
+      directions05
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update first paragraph.",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      0u,
+      17u,
+      directions05
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update from character 29",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      29u,
+      134u,
+      directions05
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update from character 163",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      163u,
+      35u,
+      directions05
+    }
+  };
+  const unsigned int numberOfTests = 8u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !GetCharactersDirectionTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp
new file mode 100644 (file)
index 0000000..b18e1e6
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * 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 SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
+//                             Length numberOfRuns,
+//                             CharacterIndex startIndex  )
+
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct SetVisualToLogicalMapData
+{
+  std::string   description;                ///< Description of the test.
+  std::string   text;                       ///< Input text.
+  unsigned int  startIndex;                 ///< The start index from where the visual to logical conversion table is set.
+  unsigned int  numberOfCharacters;         ///< The number of characters to set.
+  Size          textArea;                   ///< The size of the area where the text is laid-out.
+  unsigned int  expectedNumberOfCharacters; ///< The expected number of characters.
+  unsigned int* visualToLogical;            ///< The expected visual to logical conversion table.
+};
+
+bool SetVisualToLogicalMapTest( const SetVisualToLogicalMapData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+  // Create the model.
+  LogicalModelPtr logicalModel = LogicalModel::New();
+  VisualModelPtr visualModel = VisualModel::New();
+  Size layoutSize;
+
+  // Create the model with the whole text.
+  CreateTextModel( data.text,
+                   data.textArea,
+                   layoutSize,
+                   logicalModel,
+                   visualModel );
+
+  // Get the visual to logical map.
+  Vector<CharacterIndex>& visualToLogicalMap = logicalModel->mVisualToLogicalMap;
+
+  // Compare the results.
+  if( data.expectedNumberOfCharacters != visualToLogicalMap.Count() )
+  {
+    std::cout << "  differetn number of characters : " << visualToLogicalMap.Count() << ", expected : " << data.expectedNumberOfCharacters << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfCharacters; ++index )
+  {
+    if( data.visualToLogical[index] != visualToLogicalMap[index] )
+    {
+      std::cout << "  different visualToLogical table : " << std::endl;
+      for( unsigned int i = 0; i < data.expectedNumberOfCharacters; ++i )
+      {
+        std::cout << visualToLogicalMap[i] << " ";
+      }
+      std::cout << std::endl;
+      std::cout << "                         expected : " << std::endl;
+      for( unsigned int i = 0; i < data.expectedNumberOfCharacters; ++i )
+      {
+        std::cout << data.visualToLogical[i] << " ";
+      }
+      std::cout << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliSetVisualToLogicalMap(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliSetVisualToLogicalMap");
+
+  unsigned int* visualToLogical01 = NULL;
+  unsigned int* visualToLogical02 = NULL;
+  unsigned int  visualToLogical03[] = { 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int  visualToLogical04[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, };
+  unsigned int  visualToLogical05[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 26u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u };
+  unsigned int  visualToLogical06[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+  unsigned int  visualToLogical07[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+  unsigned int  visualToLogical08[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+  unsigned int  visualToLogical09[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+
+  struct SetVisualToLogicalMapData data[] =
+  {
+    {
+      "Zero characters text",
+      "",
+      0u,
+      0u,
+      Size( 100.f, 300.f ),
+      0u,
+      visualToLogical01
+    },
+    {
+      "Left to right text only",
+      "Hello world",
+      0u,
+      11u,
+      Size( 100.f, 300.f ),
+      0u,
+      visualToLogical02
+    },
+    {
+      "Right to left text only",
+      "مرحبا بالعالم",
+      0u,
+      13u,
+      Size( 100.f, 300.f ),
+      13u,
+      visualToLogical03
+    },
+    {
+      "Mix of left to right and right to left text.",
+      "Hello world, مرحبا بالعالم",
+      0u,
+      26u,
+      Size( 100.f, 300.f ),
+      26u,
+      visualToLogical04
+    },
+    {
+      "Mix of left to right and right to left text.",
+      "Hello world, \nمرحبا بالعالم",
+      0u,
+      27u,
+      Size( 100.f, 300.f ),
+      27u,
+      visualToLogical05
+    },
+    {
+      "Mix of left to right and right to left text.",
+      "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+      0u,
+      107u,
+      Size( 100.f, 300.f ),
+      107u,
+      visualToLogical06
+    },
+    {
+      "Mix of left to right and right to left text. Updates from character index 5",
+      "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+      5u,
+      107u,
+      Size( 100.f, 300.f ),
+      107u,
+      visualToLogical07
+    },
+    {
+      "Mix of left to right and right to left text. Updates from character index 39",
+      "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+      39u,
+      107u,
+      Size( 100.f, 300.f ),
+      107u,
+      visualToLogical08
+    },
+    {
+      "Mix of left to right and right to left text. Updates from character index 70",
+      "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+      70u,
+      107u,
+      Size( 100.f, 300.f ),
+      107u,
+      visualToLogical09
+    }
+  };
+  const unsigned int numberOfTests = 9u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !SetVisualToLogicalMapTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp
new file mode 100644 (file)
index 0000000..10f910c
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * 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 "toolkit-text-model.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/metrics.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-controller-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Frees previously allocated bidirectional resources.
+ *
+ * @param[in] bidirectionalLineInfo Bidirectional info per line.
+ * @param[in] index Index to the first line with bidirectional info to be freed.
+ */
+void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
+                                         uint32_t index )
+{
+  // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+  for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
+         endIt = bidirectionalLineInfo.End();
+       it != endIt;
+       ++it )
+  {
+    BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+    free( bidiLineInfo.visualToLogicalMap );
+  }
+}
+
+/**
+ * @brief Clear all the model data except for LogicalModel::mText.
+ *
+ * @param[in] characterIndex Clear data starting from the index.
+ */
+void ClearModelData( CharacterIndex characterIndex,
+                     LogicalModelPtr logicalModel,
+                     VisualModelPtr visualModel )
+{
+  // n.b. This does not Clear the mText from mLogicalModel
+
+  // Frees previously allocated resources.
+  FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
+
+  logicalModel->mScriptRuns.Clear();
+  logicalModel->mFontRuns.Clear();
+  logicalModel->mWordBreakInfo.Clear();
+  logicalModel->mBidirectionalParagraphInfo.Clear();
+  logicalModel->mCharacterDirections.Clear();
+  logicalModel->mBidirectionalLineInfo.Clear();
+  logicalModel->mLogicalToVisualMap.Clear();
+  logicalModel->mVisualToLogicalMap.Clear();
+  visualModel->mGlyphs.Clear();
+  visualModel->mGlyphsToCharacters.Clear();
+  visualModel->mCharactersToGlyph.Clear();
+  visualModel->mCharactersPerGlyph.Clear();
+  visualModel->mGlyphsPerCharacter.Clear();
+  visualModel->mGlyphPositions.Clear();
+  visualModel->mLines.Clear();
+  visualModel->mColorRuns.Clear();
+
+  visualModel->ClearCaches();
+}
+
+void CreateTextModel( const std::string& text,
+                      const Size& textArea,
+                      Size& layoutSize,
+                      LogicalModelPtr logicalModel,
+                      VisualModelPtr visualModel )
+{
+  // 1) Convert to utf32
+  Vector<Character>& utf32Characters = logicalModel->mText;
+  utf32Characters.Resize( text.size() );
+
+  const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( text.c_str() ),
+                                                   text.size(),
+                                                   &utf32Characters[0u] );
+  utf32Characters.Resize( numberOfCharacters );
+
+  // 2) Set the break and paragraph info.
+  Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
+  lineBreakInfo.Resize( numberOfCharacters );
+
+  SetLineBreakInfo( utf32Characters, lineBreakInfo );
+
+  if( 0u == numberOfCharacters )
+  {
+    // Nothing else to do if the number of characters is zero.
+    return;
+  }
+
+  // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
+  Vector<WordBreakInfo>& wordBreakInfo = logicalModel->mWordBreakInfo;
+  wordBreakInfo.Resize( numberOfCharacters );
+
+  SetWordBreakInfo( utf32Characters,
+                    0u,
+                    numberOfCharacters,
+                    wordBreakInfo );
+
+  // 3) Set the script info.
+  MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+  Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
+  multilanguageSupport.SetScripts( utf32Characters,
+                                   0u,
+                                   numberOfCharacters,
+                                   scripts );
+
+  // 4) Set the font info
+  Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
+  Vector<FontRun>& validFonts = logicalModel->mFontRuns;
+
+  // The default font id.
+  FontDefaults fontDefaults;
+  fontDefaults.mFontDescription.family = "";
+  fontDefaults.familyDefined = true;
+  fontDefaults.mDefaultPointSize = 12.f;
+  fontDefaults.sizeDefined = true;
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  const FontId defaultFontId = fontDefaults.GetFontId( fontClient );
+
+  // Validates the fonts. If there is a character with no assigned font it sets a default one.
+  // After this call, fonts are validated.
+  multilanguageSupport.ValidateFonts( utf32Characters,
+                                      scripts,
+                                      fontDescriptionRuns,
+                                      defaultFontId,
+                                      0u,
+                                      numberOfCharacters,
+                                      validFonts );
+
+  // 5) Set the bidirectional info per paragraph.
+  Vector<Character> mirroredUtf32Characters;
+  bool textMirrored = false;
+
+  // Reserve some space for the vector of paragraph's bidirectional info.
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+
+  // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+  SetBidirectionalInfo( utf32Characters,
+                        scripts,
+                        lineBreakInfo,
+                        0u,
+                        numberOfCharacters,
+                        bidirectionalInfo );
+
+  // 6) Set character directions.
+  Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
+  if( 0u != bidirectionalInfo.Count() )
+  {
+    // Only set the character directions if there is right to left characters.
+    GetCharactersDirection( bidirectionalInfo,
+                            numberOfCharacters,
+                            0u,
+                            numberOfCharacters,
+                            characterDirections );
+
+
+    // This paragraph has right to left text. Some characters may need to be mirrored.
+    textMirrored = GetMirroredText( utf32Characters,
+                                    characterDirections,
+                                    bidirectionalInfo,
+                                    0u,
+                                    numberOfCharacters,
+                                    mirroredUtf32Characters );
+  }
+  else
+  {
+    // There is no right to left characters. Clear the directions vector.
+    characterDirections.Clear();
+  }
+
+  // 7) Shape the text.
+
+  Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
+  Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
+  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,
+             glyphs,
+             glyphsToCharactersMap,
+             charactersPerGlyph,
+             newParagraphGlyphs );
+
+  // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+  visualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
+  visualModel->CreateCharacterToGlyphTable( numberOfCharacters );
+
+  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
+
+  // 8) Get the glyph metrics
+  MetricsPtr metrics = Metrics::New( fontClient );
+
+  const GlyphIndex glyphIndex = currentNumberOfGlyphs;
+
+  GlyphInfo* glyphsBuffer = glyphs.Begin() + glyphIndex;
+  metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
+
+  // Update the width and advance of all new paragraph characters.
+  for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
+         endIt = newParagraphGlyphs.End();
+       it != endIt;
+       ++it )
+  {
+    const GlyphIndex index = *it;
+    GlyphInfo& glyph = *( glyphsBuffer + ( index - glyphIndex ) );
+
+    glyph.xBearing = 0.f;
+    glyph.width = 0.f;
+    glyph.advance = 0.f;
+  }
+
+  // 9) Layout the text
+  LayoutEngine layoutEngine;
+  layoutEngine.SetMetrics( metrics );
+  layoutEngine.SetLayout( LayoutEngine::MULTI_LINE_BOX );
+
+  // Set the layout parameters.
+  const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+  const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+  LayoutParameters layoutParameters( textArea,
+                                     utf32Characters.Begin(),
+                                     lineBreakInfo.Begin(),
+                                     wordBreakInfo.Begin(),
+                                     ( 0u != characterDirections.Count() ) ? characterDirections.Begin() : NULL,
+                                     glyphs.Count(),
+                                     glyphs.Begin(),
+                                     glyphsToCharactersMap.Begin(),
+                                     charactersPerGlyph.Begin() );
+
+  // Get the character to glyph conversion table and set into the layout.
+  layoutParameters.charactersToGlyphsBuffer = charactersToGlyph.Begin();
+  // Get the glyphs per character table and set into the layout.
+  layoutParameters.glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
+
+  Vector<LineRun>& lines = visualModel->mLines;
+
+  Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
+  glyphPositions.Resize( numberOfGlyphs );
+
+  layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( logicalModel->mText.Count() - 1u ) ) );
+
+  layoutEngine.LayoutText( layoutParameters,
+                           glyphPositions,
+                           lines,
+                           layoutSize );
+
+  // 10) Reorder the lines
+  if( 0u != bidirectionalInfo.Count() )
+  {
+    Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo;
+
+    // Get the lines
+    const Length numberOfLines = lines.Count();
+
+    // Reorder the lines.
+    bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
+    ReorderLines( bidirectionalInfo,
+                  0u,
+                  numberOfCharacters,
+                  lines,
+                  bidirectionalLineInfo );
+
+    // Set the bidirectional info per line into the layout parameters.
+    layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
+    layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
+
+    // Set the bidirectional info into the model.
+    logicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
+                                         layoutParameters.numberOfBidirectionalInfoRuns,
+                                         0u,
+                                         numberOfCharacters );
+
+    // Re-layout the text. Reorder those lines with right to left characters.
+    layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
+                                           glyphPositions );
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.h
new file mode 100644 (file)
index 0000000..02dbbcd
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __DALI_TOOLKIT_TEXT_MODEL_H__
+#define __DALI_TOOLKIT_TEXT_MODEL_H__
+
+/*
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/logical-model-impl.h>
+#include <dali-toolkit/internal/text/visual-model-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Creates and fills all the vectors of a text model: characters in utf32, segmentation info,
+ * scripts, fonts, bidi info, glyphs, conversion tables, etc.
+ *
+ * @param[in] text The given text.
+ * @param[in] textArea The area where to layout the text.
+ * @param[out] layoutSize The laid-out size.
+ * @param[out] Pointer to a logical text model instance.
+ * @param[out] Pointer to a visual text model instance.
+ */
+void CreateTextModel( const std::string& text,
+                      const Size& textArea,
+                      Size& layoutSize,
+                      LogicalModelPtr logicalModel,
+                      VisualModelPtr visualModel );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_MODEL_H__
index c09c03c..57dc613 100644 (file)
@@ -86,13 +86,32 @@ void GetLines( const BidirectionalParagraphInfoRun& paragraphInfo,
 void SetBidirectionalInfo( const Vector<Character>& text,
                            const Vector<ScriptRun>& scripts,
                            const Vector<LineBreakInfo>& lineBreakInfo,
+                           CharacterIndex startIndex,
+                           Length numberOfCharacters,
                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
 {
+  // Find where to insert the new paragraphs.
+  BidirectionalRunIndex bidiInfoIndex = 0u;
+  for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
+         endIt = bidirectionalInfo.End();
+       it != endIt;
+       ++it )
+  {
+    const BidirectionalParagraphInfoRun& run = *it;
+
+    if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+    {
+      // Found where to insert the bidi info.
+      break;
+    }
+    ++bidiInfoIndex;
+  }
+
   // Traverse the script runs. If there is one with a right to left script, create the bidirectional info for the paragraph containing that script is needed.
   // From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK.
 
   // Index pointing the first character of the current paragraph.
-  CharacterIndex paragraphCharacterIndex = 0u;
+  CharacterIndex paragraphCharacterIndex = startIndex;
 
   // Pointer to the text buffer.
   const Character* textBuffer = text.Begin();
@@ -100,75 +119,106 @@ void SetBidirectionalInfo( const Vector<Character>& text,
   // Pointer to the line break info buffer.
   const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
 
-  // The number of characters.
-  const Length numberOfCharacters = text.Count();
-
   // Handle to the bidirectional info module in text-abstraction.
   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
 
+  const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
+  bool hasRightToLeftScript = false;
+
   for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
          endIt = scripts.End();
        it != endIt;
        ++it )
   {
     const ScriptRun& scriptRun = *it;
-    const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters;
+    const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters - 1u;
+
+    if( startIndex > lastScriptRunIndex )
+    {
+      // Skip the run as it has already been processed.
+      continue;
+    }
+
+    if( lastCharacter <= scriptRun.characterRun.characterIndex )
+    {
+      // Do not get bidirectional info beyond startIndex + numberOfCharacters.
+      break;
+    }
+
+    if( !hasRightToLeftScript && TextAbstraction::IsRightToLeftScript( scriptRun.script ) )
+    {
+      // The script is right to left.
+      hasRightToLeftScript = true;
+    }
 
-    if( ( lastScriptRunIndex > paragraphCharacterIndex ) &&        // It isn't part of a previous paragraph.
-        TextAbstraction::IsRightToLeftScript( scriptRun.script ) ) // The script is right to left.
+    if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + lastScriptRunIndex ) )
     {
-      // Find the paragraphs which contains this script run.
-      // Consider:
-      //  1) Different paragraphs may contain this script run.
-      //  ------||------------------- rtl sr ------------------------||-------------------
-      //  --||----- p -----||------------------ p -------------||-------- p ------||------
-      //
-      //  2) The paragraph which contains this script run may contain other right to left script runs.
-      //  -----||--- rtl sr ---||---- ltr sr ----||---------- rtl sr -----------||--------
-      //  -----||---------------------------------- p -----------------------------------|
-
-      while( lastScriptRunIndex > paragraphCharacterIndex )
+      // A new paragraph has been found.
+
+      if( hasRightToLeftScript )
       {
-        // There is a paragraph which contains the current script.
-
-        Length index = paragraphCharacterIndex;
-        while( ( index < numberOfCharacters ) && ( paragraphCharacterIndex < lastScriptRunIndex ) )
-        {
-          if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) )
-          {
-            if( index >= scriptRun.characterRun.characterIndex )
-            {
-              // The Bidirectional run must have the same number of characters than the paragraph.
-              BidirectionalParagraphInfoRun bidirectionalRun;
-              bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
-              bidirectionalRun.characterRun.numberOfCharacters = ( index - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
-
-              // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
-              bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
-                                                                                         bidirectionalRun.characterRun.numberOfCharacters );
-
-              bidirectionalInfo.PushBack( bidirectionalRun );
-            }
-
-            // Update the character index of the next paragraph.
-            paragraphCharacterIndex = index + 1u;
-          }
-          ++index;
-        }
-
-        // The last character is always a must-break, so there is no need to check if there is characters left.
+        // The Bidirectional run must have the same number of characters than the paragraph.
+        BidirectionalParagraphInfoRun bidirectionalRun;
+        bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
+        bidirectionalRun.characterRun.numberOfCharacters = ( lastScriptRunIndex - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
+
+        // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
+        bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
+                                                                                   bidirectionalRun.characterRun.numberOfCharacters );
+
+        bidirectionalInfo.Insert( bidirectionalInfo.Begin() + bidiInfoIndex, bidirectionalRun );
+        ++bidiInfoIndex;
       }
+
+      // Point to the next paragraph.
+      paragraphCharacterIndex = lastScriptRunIndex + 1u;
+
+      // Reset whether there is a right to left script.
+      hasRightToLeftScript = false;
     }
   }
+
+  // Update indices of the bidi runs.
+  for( Vector<BidirectionalParagraphInfoRun>::Iterator it = bidirectionalInfo.Begin() + bidiInfoIndex,
+         endIt = bidirectionalInfo.End();
+       it != endIt;
+       ++it )
+  {
+    BidirectionalParagraphInfoRun& run = *it;
+
+    run.characterRun.characterIndex += numberOfCharacters;
+  }
 }
 
 void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                   CharacterIndex startIndex,
+                   Length numberOfCharacters,
                    Vector<LineRun>& lineRuns,
                    Vector<BidirectionalLineInfoRun>& lineInfoRuns )
 {
+  // Find where to insert the new paragraphs.
+  BidirectionalLineRunIndex bidiLineInfoIndex = 0u;
+  for( Vector<BidirectionalLineInfoRun>::ConstIterator it = lineInfoRuns.Begin(),
+         endIt = lineInfoRuns.End();
+       it != endIt;
+       ++it )
+  {
+    const BidirectionalLineInfoRun& run = *it;
+
+    if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+    {
+      // Found where to insert the bidi line info.
+      break;
+    }
+    ++bidiLineInfoIndex;
+  }
+
   // Handle to the bidirectional info module in text-abstraction.
   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
 
+  const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
   // Keep an index to the first line to be checked if it's contained inside the paragraph.
   // Avoids check the lines from the beginning for each paragraph.
   unsigned int lineIndex = 0u;
@@ -179,6 +229,19 @@ void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInf
        ++it )
   {
     const BidirectionalParagraphInfoRun& paragraphInfo = *it;
+
+    if( paragraphInfo.characterRun.characterIndex < startIndex )
+    {
+      // Do not process, the paragraph has already been processed.
+      continue;
+    }
+
+    if( lastCharacter <= paragraphInfo.characterRun.characterIndex )
+    {
+      // Do not process paragraphs beyond startIndex + numberOfCharacters.
+      break;
+    }
+
     const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( paragraphInfo.bidirectionalInfoIndex );
 
     // Get the lines for this paragraph.
@@ -225,14 +288,28 @@ void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInf
       }
 
       // Push the run into the vector.
-      lineInfoRuns.PushBack( lineInfoRun );
+      lineInfoRuns.Insert( lineInfoRuns.Begin() + bidiLineInfoIndex, lineInfoRun );
+      ++bidiLineInfoIndex;
     }
   }
+
+  // Update indices of the bidi runs.
+  for( Vector<BidirectionalLineInfoRun>::Iterator it = lineInfoRuns.Begin() + bidiLineInfoIndex,
+         endIt = lineInfoRuns.End();
+       it != endIt;
+       ++it )
+  {
+    BidirectionalLineInfoRun& run = *it;
+
+    run.characterRun.characterIndex += numberOfCharacters;
+  }
 }
 
 bool GetMirroredText( const Vector<Character>& text,
                       const Vector<CharacterDirection>& directions,
                       const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                      CharacterIndex startIndex,
+                      Length numberOfCharacters,
                       Vector<Character>& mirroredText )
 {
   bool hasTextMirrored = false;
@@ -245,6 +322,9 @@ bool GetMirroredText( const Vector<Character>& text,
   Character* mirroredTextBuffer = mirroredText.Begin();
   CharacterDirection* directionsBuffer = directions.Begin();
 
+  CharacterIndex index = startIndex;
+  const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
   // Traverse the paragraphs and mirror the right to left ones.
   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
          endIt = bidirectionalInfo.End();
@@ -253,6 +333,19 @@ bool GetMirroredText( const Vector<Character>& text,
   {
     const BidirectionalParagraphInfoRun& paragraph = *it;
 
+    if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
+    {
+      // Skip the paragraph as it has already been processed.
+      continue;
+    }
+
+    if( lastCharacter <= paragraph.characterRun.characterIndex )
+    {
+      // Do not get mirror characters beyond startIndex + numberOfCharacters.
+      break;
+    }
+
+    index += paragraph.characterRun.numberOfCharacters;
     const bool tmpMirrored = bidirectionalSupport.GetMirroredText( mirroredTextBuffer + paragraph.characterRun.characterIndex,
                                                                    directionsBuffer + paragraph.characterRun.characterIndex,
                                                                    paragraph.characterRun.numberOfCharacters );
@@ -264,13 +357,36 @@ bool GetMirroredText( const Vector<Character>& text,
 }
 
 void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                             Length totalNumberOfCharacters,
+                             CharacterIndex startIndex,
+                             Length numberOfCharacters,
                              Vector<CharacterDirection>& directions )
 {
   // Handle to the bidirectional info module in text-abstraction.
   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
 
-  CharacterIndex index = 0u;
-  CharacterDirection* directionsBuffer = directions.Begin();
+  // Resize the vector.
+  directions.Resize( totalNumberOfCharacters );
+
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+  CharacterDirection* directionsBuffer = NULL;
+  Vector<CharacterDirection> newDirections;
+
+  if( updateCurrentBuffer )
+  {
+    newDirections.Resize( numberOfCharacters );
+    directionsBuffer = newDirections.Begin();
+  }
+  else
+  {
+    directionsBuffer = directions.Begin();
+  }
+
+  const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+  CharacterIndex index = startIndex;
+
   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
          endIt = bidirectionalInfo.End();
        it != endIt;
@@ -278,17 +394,46 @@ void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidire
   {
     const BidirectionalParagraphInfoRun& paragraph = *it;
 
-    // Fills with left to right those paragraphs without right to left characters.
-    memset( directionsBuffer + index, false, ( paragraph.characterRun.characterIndex - index ) * sizeof( bool ) );
-    index += paragraph.characterRun.numberOfCharacters;
+    if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
+    {
+      // Skip the paragraph as it has already been processed.
+      continue;
+    }
 
+    if( lastCharacter <= paragraph.characterRun.characterIndex )
+    {
+      // Do not get the character directions beyond startIndex + numberOfCharacters.
+      break;
+    }
+
+    // Set the directions of any previous left to right characters.
+    const Length numberOfLeftToRightCharacters = paragraph.characterRun.characterIndex - index;
+    if( numberOfLeftToRightCharacters > 0u )
+    {
+      memset( directionsBuffer + index - startIndex, false, numberOfLeftToRightCharacters * sizeof( bool ) );
+    }
+
+    // Set the directions of the bidirectional text.
     bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex,
-                                                 directionsBuffer + paragraph.characterRun.characterIndex,
+                                                 directionsBuffer + paragraph.characterRun.characterIndex - startIndex,
                                                  paragraph.characterRun.numberOfCharacters );
+
+    // Update the index.
+    index += paragraph.characterRun.numberOfCharacters + numberOfLeftToRightCharacters;
   }
 
   // Fills with left to right those paragraphs without right to left characters.
-  memset( directionsBuffer + index, false, ( directions.Count() - index ) * sizeof( bool ) );
+  memset( directionsBuffer + index - startIndex, false, ( lastCharacter - index ) * sizeof( bool ) );
+
+  // If the direction info is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    // Insert the directions in the given buffer.
+    directions.Insert( directions.Begin() + startIndex,
+                       newDirections.Begin(),
+                       newDirections.End() );
+    directions.Resize( totalNumberOfCharacters );
+  }
 }
 
 } // namespace Text
index e87f866..39ec9d6 100644 (file)
@@ -42,11 +42,15 @@ namespace Text
  * @param[in] text Vector of UTF-32 characters.
  * @param[in] scripts Vector containing the script runs for the whole text.
  * @param[in] lineBreakInfo The line break info.
+ * @param[in] startIndex The character from where the bidirectional info is set.
+ * @param[in] numberOfCharacters The number of characters.
  * @param[out] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
  */
 void SetBidirectionalInfo( const Vector<Character>& text,
                            const Vector<ScriptRun>& scripts,
                            const Vector<LineBreakInfo>& lineBreakInfo,
+                           CharacterIndex startIndex,
+                           Length numberOfCharacters,
                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo );
 
 /**
@@ -60,10 +64,14 @@ void SetBidirectionalInfo( const Vector<Character>& text,
  * @pre The @p visualModel needs to have the laid-out lines info set.
  *
  * @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] startIndex The character from where the bidirectional info is set.
+ * @param[in] numberOfCharacters The number of characters.
  * @param[in,out] lineRuns The line runs converted to characters.
  * @param[out] lineInfoRuns line runs with the visual to logical conversion maps.
  */
 void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                   CharacterIndex startIndex,
+                   Length numberOfCharacters,
                    Vector<LineRun>& lineRuns,
                    Vector<BidirectionalLineInfoRun>& lineInfoRuns );
 
@@ -73,6 +81,8 @@ void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInf
  * @param[in] text The text.
  * @param[in] directions Vector with the direction of each paragraph.
  * @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] startIndex The character from where the text is mirrored.
+ * @param[in] numberOfCharacters The number of characters.
  * @param[out] mirroredText The mirroredText.
  *
  * @return @e true if a character has been replaced.
@@ -80,6 +90,8 @@ void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInf
 bool GetMirroredText( const Vector<Character>& text,
                       const Vector<CharacterDirection>& directions,
                       const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                      CharacterIndex startIndex,
+                      Length numberOfCharacters,
                       Vector<Character>& mirroredText );
 
 /**
@@ -89,9 +101,15 @@ bool GetMirroredText( const Vector<Character>& text,
  * @pre The @p logicalModel needs to have the bidirectional info indices for each paragraph set.
  *
  * @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] totalNumberOfCharacters The number of characters of the whole text.
+ * @param[in] startIndex The character from where the direction info is set.
+ * @param[in] numberOfCharacters The number of characters.
  * @param[out] directions The direction, @e false is left to right and @e true is right to left, of each character of the paragraph.
  */
 void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                             Length totalNumberOfCharacters,
+                             CharacterIndex startIndex,
+                             Length numberOfCharacters,
                              Vector<CharacterDirection>& directions );
 
 } // namespace Text
index 822f9f8..8af3e91 100644 (file)
@@ -79,168 +79,166 @@ CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex character
 }
 
 void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
-                                          Length numberOfRuns )
+                                          Length numberOfRuns,
+                                          CharacterIndex startIndex,
+                                          Length numberOfCharacters )
 {
-  if( 0u == numberOfRuns )
-  {
-    mVisualToLogicalMap.Clear();
-    mLogicalToVisualMap.Clear();
-    mVisualToLogicalCursorMap.Clear();
-  }
-  else
-  {
-    const Length numberOfCharacters = mText.Count();
-    mVisualToLogicalMap.Resize( numberOfCharacters );
-    mLogicalToVisualMap.Resize( numberOfCharacters );
+  mVisualToLogicalMap.Resize( numberOfCharacters );
+  mLogicalToVisualMap.Resize( numberOfCharacters );
 
-    const Length numberOfCharactersPlus = numberOfCharacters + 1u;
-    mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
+  const Length numberOfCharactersPlus = numberOfCharacters + 1u;
+  mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
 
-    CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
-    CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
+  CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
+  CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
 
-    CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
+  CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
 
-    CharacterIndex lastIndex = 0u;
-    for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
-    {
-      const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
+  CharacterIndex lastIndex = startIndex;
+  for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
+  {
+    const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
 
-      if( lastIndex < bidiLineInfo.characterRun.characterIndex )
-      {
-        // Fill with the identity.
-        for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
-        {
-          *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
-        }
-      }
+    if( bidiLineInfo.characterRun.characterIndex + bidiLineInfo.characterRun.numberOfCharacters <= startIndex )
+    {
+      // Skip this paragraph. It has been already processed.
+      continue;
+    }
 
-      // Fill the conversion table of the run.
-      for( CharacterIndex index = 0u;
-           index < bidiLineInfo.characterRun.numberOfCharacters;
-           ++index, ++lastIndex )
+    if( lastIndex < bidiLineInfo.characterRun.characterIndex )
+    {
+      // Fill with the identity.
+      for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
       {
-        *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
+        *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
       }
     }
 
-    // Complete with the identity if there are some left to right characters after the last right to left.
-    for( ; lastIndex < numberOfCharacters; ++lastIndex )
+    // Fill the conversion table of the run.
+    for( CharacterIndex index = 0u;
+         index < bidiLineInfo.characterRun.numberOfCharacters;
+         ++index, ++lastIndex )
     {
-      *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
+      *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
     }
+  }
 
-    // Sets the logical to visual conversion map.
-    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
-    {
-      *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
-    }
+  // Complete with the identity if there are some left to right characters after the last right to left.
+  for( ; lastIndex < numberOfCharacters; ++lastIndex )
+  {
+    *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
+  }
+
+  // Sets the logical to visual conversion map.
+  for( CharacterIndex index = startIndex; index < numberOfCharacters; ++index )
+  {
+    *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
+  }
 
-    // Sets the visual to logical conversion map for cursor positions.
+  // Sets the visual to logical conversion map for cursor positions.
 
-    const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
-    BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
-    BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
+  const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
+  BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
+  BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
 
-    const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
+  const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
+
+  Length bidirectionalParagraphIndex = 0u;
+  bool isRightToLeftParagraph = false;
+  for( CharacterIndex index = startIndex; index < numberOfCharactersPlus; ++index )
+  {
+    if( bidirectionalParagraph &&
+        ( bidirectionalParagraph->characterRun.characterIndex == index ) )
+    {
+      isRightToLeftParagraph = *( modelCharacterDirections + index );
+    }
 
-    Length bidirectionalParagraphIndex = 0u;
-    bool isRightToLeftParagraph = false;
-    for( CharacterIndex index = 0u; index < numberOfCharactersPlus; ++index )
+    if( 0u == index )
     {
-      if( bidirectionalParagraph &&
-          ( bidirectionalParagraph->characterRun.characterIndex == index ) )
+      if( isRightToLeftParagraph )
       {
-        isRightToLeftParagraph = *( modelCharacterDirections + index );
+        *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
       }
-
-      if( 0u == index )
+      else // else logical position is zero.
       {
-        if( isRightToLeftParagraph )
-        {
-          *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
-        }
-        else // else logical position is zero.
-        {
-          *( modelVisualToLogicalCursorMap + index ) = 0u;
-        }
+        *( modelVisualToLogicalCursorMap + index ) = 0u;
       }
-      else if( numberOfCharacters == index )
+    }
+    else if( numberOfCharacters == index )
+    {
+      if( isRightToLeftParagraph )
       {
-        if( isRightToLeftParagraph )
+        *( modelVisualToLogicalCursorMap + index ) = 0u;
+      }
+      else // else logical position is the number of characters.
+      {
+        *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
+      }
+    }
+    else
+    {
+      // Get the character indexed by  index - 1 and index
+      // and calculate the logical position according the directions of
+      // both characters and the direction of the paragraph.
+
+      const CharacterIndex previousIndex = index - 1u;
+      const CharacterIndex logicalPosition0 = *( modelVisualToLogicalMapBuffer + previousIndex );
+      const CharacterIndex logicalPosition1 = *( modelVisualToLogicalMapBuffer + index );
+
+      const CharacterDirection direction0 = *( modelCharacterDirections + logicalPosition0 );
+      const CharacterDirection direction1 = *( modelCharacterDirections + logicalPosition1 );
+
+      if( direction0 == direction1 )
+      {
+        // Both glyphs have the same direction.
+        if( direction0 )
         {
-          *( modelVisualToLogicalCursorMap + index ) = 0u;
+          *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
         }
-        else // else logical position is the number of characters.
+        else
         {
-          *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
+          *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
         }
       }
       else
       {
-        // Get the character indexed by  index - 1 and index
-        // and calculate the logical position according the directions of
-        // both characters and the direction of the paragraph.
-
-        const CharacterIndex previousIndex = index - 1u;
-        const CharacterIndex logicalPosition0 = *( modelVisualToLogicalMapBuffer + previousIndex );
-        const CharacterIndex logicalPosition1 = *( modelVisualToLogicalMapBuffer + index );
-
-        const CharacterDirection direction0 = *( modelCharacterDirections + logicalPosition0 );
-        const CharacterDirection direction1 = *( modelCharacterDirections + logicalPosition1 );
-
-        if( direction0 == direction1 )
+        if( isRightToLeftParagraph )
         {
-          // Both glyphs have the same direction.
-          if( direction0 )
+          if( direction1 )
           {
-            *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
+            *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
           }
           else
           {
-            *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
+            *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
           }
         }
         else
         {
-          if( isRightToLeftParagraph )
+          if( direction0 )
           {
-            if( direction1 )
-            {
-              *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
-            }
-            else
-            {
-              *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
-            }
+            *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
           }
           else
           {
-            if( direction0 )
-            {
-              *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
-            }
-            else
-            {
-              *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
-            }
+            *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
           }
         }
       }
+    }
 
-      if( bidirectionalParagraph &&
-          ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
+    if( bidirectionalParagraph &&
+        ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
+    {
+      isRightToLeftParagraph = false;
+      ++bidirectionalParagraphIndex;
+      if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
       {
-        isRightToLeftParagraph = false;
-        ++bidirectionalParagraphIndex;
-        if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
-        {
-          bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
-        }
-        else
-        {
-          bidirectionalParagraph = NULL;
-        }
+        bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
+      }
+      else
+      {
+        bidirectionalParagraph = NULL;
       }
     }
   }
index 7a28ba6..7085d79 100644 (file)
@@ -96,9 +96,13 @@ public:
    *
    * @param[in] bidirectionalInfo Pointer to a buffer with all the bidirectional info runs.
    * @param[in] numberOfRuns The number of bidirectional info runs.
+   * @param[in] startIndex Character index from where the conversion tables are set.
+   * @param[in] numberOfCharacters The number of characters.
    */
   void SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
-                              Length numberOfRuns );
+                              Length numberOfRuns,
+                              CharacterIndex startIndex,
+                              Length numberOfCharacters );
 
   /**
    * @brief Retrieves the logical character index for the given visual character index.
@@ -109,6 +113,8 @@ public:
    */
   CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const;
 
+  // Text style.
+
   /**
    * @brief Updates the text's style runs with the added or removed text.
    *
index 2a76cb2..9458933 100644 (file)
@@ -416,15 +416,18 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     SetBidirectionalInfo( utf32Characters,
                           scripts,
                           lineBreakInfo,
+                          startIndex,
+                          requestedNumberOfCharacters,
                           bidirectionalInfo );
 
     if( 0u != bidirectionalInfo.Count() )
     {
       // Only set the character directions if there is right to left characters.
       Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
-      directions.Resize( numberOfCharacters );
-
       GetCharactersDirection( bidirectionalInfo,
+                              numberOfCharacters,
+                              startIndex,
+                              requestedNumberOfCharacters,
                               directions );
 
       // This paragraph has right to left text. Some characters may need to be mirrored.
@@ -433,6 +436,8 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
       textMirrored = GetMirroredText( utf32Characters,
                                       directions,
                                       bidirectionalInfo,
+                                      startIndex,
+                                      requestedNumberOfCharacters,
                                       mirroredUtf32Characters );
     }
     else
index 8a500f7..740e948 100644 (file)
@@ -1382,32 +1382,36 @@ bool Controller::DoRelayout( const Size& size,
       if( REORDER & operations )
       {
         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
+        Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mLogicalModel->mBidirectionalLineInfo;
 
         // Check first if there are paragraphs with bidirectional info.
         if( 0u != bidirectionalInfo.Count() )
         {
           // Get the lines
           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
+          const CharacterIndex startIndex = 0u;
+          Length requestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
 
           // Reorder the lines.
-          Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
-          lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
+          bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
           ReorderLines( bidirectionalInfo,
+                        startIndex,
+                        requestedNumberOfCharacters,
                         lines,
-                        lineBidirectionalInfoRuns );
-
-          // Set the bidirectional info into the model.
-          const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
-          mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
-                                                       numberOfBidirectionalInfoRuns );
+                        bidirectionalLineInfo );
 
           // Set the bidirectional info per line into the layout parameters.
-          layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
-          layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
+          layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
+          layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
+
+          // Set the bidirectional info into the model.
+          mImpl->mLogicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
+                                                       layoutParameters.numberOfBidirectionalInfoRuns,
+                                                       startIndex,
+                                                       requestedNumberOfCharacters );
 
           // Get the character to glyph conversion table and set into the layout.
           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
-
           // Get the glyphs per character table and set into the layout.
           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
 
@@ -1416,15 +1420,18 @@ bool Controller::DoRelayout( const Size& size,
                                                          glyphPositions );
 
           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
-          for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
-                 endIt = lineBidirectionalInfoRuns.End();
+          for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin(),
+                 endIt = bidirectionalLineInfo.End();
                it != endIt;
                ++it )
           {
             BidirectionalLineInfoRun& bidiLineInfo = *it;
 
             free( bidiLineInfo.visualToLogicalMap );
+            bidiLineInfo.visualToLogicalMap = NULL;
           }
+
+          bidirectionalLineInfo.Clear();
         }
       } // REORDER
 
index dbb29cd..4879090 100644 (file)
@@ -52,12 +52,13 @@ typedef TextAbstraction::LineBreakInfo      LineBreakInfo;      ///< Line break
 typedef TextAbstraction::WordBreakInfo      WordBreakInfo;      ///< Word break info (break, no break). Possible values are: @e WORD_BREAK and @e WORD_NO_BREAK (in the TextAbstraction namespace).
 typedef TextAbstraction::CharacterDirection CharacterDirection; ///< The character's direction: @e false is left to right, @e true is right to left.
 
-typedef uint32_t                         GlyphIndex;            ///< An index into an array of glyphs.
-typedef uint32_t                         ScriptRunIndex;        ///< An index into an array of script runs.
-typedef uint32_t                         FontRunIndex;          ///< An index into an array of font runs.
-typedef uint32_t                         UnderlineRunIndex;     ///< An index into an array of underline runs.
-typedef uint32_t                         BidirectionalRunIndex; ///< An index into an array of font runs.
-typedef uint32_t                         LineIndex;             ///< An index into an array of lines.
+typedef uint32_t                         GlyphIndex;                ///< An index into an array of glyphs.
+typedef uint32_t                         ScriptRunIndex;            ///< An index into an array of script runs.
+typedef uint32_t                         FontRunIndex;              ///< An index into an array of font runs.
+typedef uint32_t                         UnderlineRunIndex;         ///< An index into an array of underline runs.
+typedef uint32_t                         BidirectionalRunIndex;     ///< An index into an array of bidirectional info.
+typedef uint32_t                         BidirectionalLineRunIndex; ///< An index into an array of bidirectional line info.
+typedef uint32_t                         LineIndex;                 ///< An index into an array of lines.
 
 } // namespace Text