[dali_2.3.20] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / utc-Dali-LogicalModel.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <iostream>
21
22 #include <dali-toolkit-test-suite-utils.h>
23 #include <dali-toolkit/dali-toolkit.h>
24 #include <dali-toolkit/internal/text/text-run-container.h>
25 #include <toolkit-text-utils.h>
26
27 using namespace Dali;
28 using namespace Toolkit;
29 using namespace Text;
30
31 // Tests the following functions.
32 //
33 // void CreateParagraphInfo( CharacterIndex startIndex,
34 //                           Length numberOfCharacters );
35 // void FindParagraphs( CharacterIndex index,
36 //                      Length numberOfCharacters,
37 //                      Vector<ParagraphRunIndex>& paragraphs );
38 // bool FetchBidirectionalLineInfo( CharacterIndex characterIndex )
39 // CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const;
40 // CharacterIndex GetLogicalCursorIndex( CharacterIndex visualCursorIndex ) const;
41
42 //////////////////////////////////////////////////////////
43
44 namespace
45 {
46 const std::string DEFAULT_FONT_DIR("/resources/fonts");
47
48 struct CreateParagraphData
49 {
50   std::string    description;                    ///< Description of the test.
51   std::string    text;                           ///< Input text.
52   CharacterIndex index;                          ///< The first character index.
53   Length         numberOfCharacters;             ///< The number of characters.
54   unsigned int   numberOfParagraphs;             ///< The expected number of paragraphs.
55   unsigned int*  indices;                        ///< The expected paragraph info indices.
56   unsigned int*  numberOfCharactersPerParagraph; ///< The expected number of characters of each paragraph.
57 };
58
59 struct FindParagraphData
60 {
61   std::string    description;        ///< Description of the test.
62   std::string    text;               ///< Input text.
63   CharacterIndex index;              ///< The first character index.
64   Length         numberOfCharacters; ///< The number of characters.
65   unsigned int   numberOfParagraphs; ///< The expected number of paragraphs.
66   unsigned int*  paragraphs;         ///< The expected paragraph info.
67 };
68
69 struct FetchBidirectionalLineInfoData
70 {
71   std::string   description;    ///< Description of the test.
72   std::string   text;           ///< Input text.
73   unsigned int  numberOfTests;  ///< The number of tests.
74   unsigned int* characterIndex; ///< The logical character index.
75   bool*         fetched;        ///< Whether the expected bidi line exists.
76   unsigned int* bidiLineIndex;  ///< Index to the expected bidi line.
77 };
78
79 struct GetLogicalCharacterIndexData
80 {
81   std::string   description;     ///< Description of the test.
82   std::string   text;            ///< Input text.
83   Size          textArea;        ///< The text area.
84   unsigned int  numberOfIndices; ///< The number of characters to set.
85   unsigned int* visualToLogical; ///< The expected visual to logical conversion table.
86   unsigned int* cachedBidiLine;  ///< The cached bidi line index for each character.
87 };
88
89 struct GetLogicalCursorIndexData
90 {
91   std::string         description;        ///< Description of the test.
92   std::string         text;               ///< Input text.
93   Size                textArea;           ///< The text area.
94   unsigned int        numberOfFonts;      ///< The number of fonts.
95   FontDescriptionRun* fontDescriptions;   ///< The font descriptions.
96   unsigned int        numberOfIndices;    ///< The number of characters to set.
97   unsigned int*       visualCursorIndex;  ///< The given cursor visual index.
98   unsigned int*       characterIndex;     ///< Index to the first logical character of the line.
99   unsigned int*       logicalCursorIndex; ///< The expected cursor logical index.
100   unsigned int*       cachedBidiLine;     ///< The cached bidi line index for each character.
101 };
102
103 bool CreateParagraphTest(const CreateParagraphData& data)
104 {
105   // 1) Create the model.
106   ModelPtr   textModel;
107   MetricsPtr metrics;
108   Size       textArea(100.f, 60.f);
109   Size       layoutSize;
110
111   Vector<FontDescriptionRun> fontDescriptionRuns;
112   LayoutOptions              options;
113   CreateTextModel(data.text,
114                   textArea,
115                   fontDescriptionRuns,
116                   options,
117                   layoutSize,
118                   textModel,
119                   metrics,
120                   false,
121                   LineWrap::WORD,
122                   false,
123                   Toolkit::DevelText::EllipsisPosition::END,
124                   0.0f, // lineSpacing
125                   0.0f  // characterSpacing
126   );
127
128   LogicalModelPtr logicalModel = textModel->mLogicalModel;
129   VisualModelPtr  visualModel  = textModel->mVisualModel;
130
131   // 2) Clear the paragraphs.
132   Vector<ParagraphRun>& paragraphs = logicalModel->mParagraphInfo;
133   ClearCharacterRuns(data.index,
134                      data.index + data.numberOfCharacters - 1u,
135                      paragraphs);
136
137   // 3) Call the LogicalModel::CreateParagraphInfo() method
138   logicalModel->CreateParagraphInfo(data.index,
139                                     data.numberOfCharacters);
140
141   // 4) Compare the results.
142   if(data.numberOfParagraphs != paragraphs.Count())
143   {
144     std::cout << "  Different number of paragraphs : " << paragraphs.Count() << ", expected : " << data.numberOfParagraphs << std::endl;
145     return false;
146   }
147
148   unsigned int index = 0u;
149   for(Vector<ParagraphRun>::ConstIterator it    = paragraphs.Begin(),
150                                           endIt = paragraphs.End();
151       it != endIt;
152       ++it, ++index)
153   {
154     const ParagraphRun& paragraph(*it);
155
156     if(data.indices[index] != paragraph.characterRun.characterIndex)
157     {
158       std::cout << "  Different character index for paragraph : " << index << ", " << paragraph.characterRun.characterIndex << ", expected : " << data.indices[index] << std::endl;
159       return false;
160     }
161     if(data.numberOfCharactersPerParagraph[index] != paragraph.characterRun.numberOfCharacters)
162     {
163       std::cout << "  Different number of characters for paragraph : " << index << ", " << paragraph.characterRun.numberOfCharacters << ", expected : " << data.numberOfCharactersPerParagraph[index] << std::endl;
164       return false;
165     }
166   }
167
168   return true;
169 }
170
171 bool FindParagraphTest(const FindParagraphData& data)
172 {
173   // 1) Create the model.
174   ModelPtr   textModel;
175   MetricsPtr metrics;
176   Size       textArea(100.f, 60.f);
177   Size       layoutSize;
178
179   Vector<FontDescriptionRun> fontDescriptionRuns;
180   LayoutOptions              options;
181   CreateTextModel(data.text,
182                   textArea,
183                   fontDescriptionRuns,
184                   options,
185                   layoutSize,
186                   textModel,
187                   metrics,
188                   false,
189                   LineWrap::WORD,
190                   false,
191                   Toolkit::DevelText::EllipsisPosition::END,
192                   0.0f, // lineSpacing
193                   0.0f  // characterSpacing
194   );
195
196   LogicalModelPtr logicalModel = textModel->mLogicalModel;
197   VisualModelPtr  visualModel  = textModel->mVisualModel;
198
199   // 2) Find the paragraphs.
200   Vector<ParagraphRunIndex> paragraphs;
201   logicalModel->FindParagraphs(data.index, data.numberOfCharacters, paragraphs);
202
203   // 3) compare the results.
204   if(data.numberOfParagraphs != paragraphs.Count())
205   {
206     return false;
207   }
208
209   unsigned int index = 0u;
210   for(Vector<ParagraphRunIndex>::ConstIterator it    = paragraphs.Begin(),
211                                                endIt = paragraphs.End();
212       it != endIt;
213       ++it, ++index)
214   {
215     const ParagraphRunIndex paragraphIndex = *it;
216
217     if(paragraphIndex != data.paragraphs[index])
218     {
219       return false;
220     }
221   }
222
223   return true;
224 }
225
226 bool FetchBidirectionalLineInfoTest(const FetchBidirectionalLineInfoData& data)
227 {
228   std::cout << "  testing : " << data.description << std::endl;
229   // Create the model.
230   ModelPtr   textModel;
231   MetricsPtr metrics;
232   Size       textArea(100.f, 300.f);
233   Size       layoutSize;
234
235   // Create the model with the whole text.
236   const Vector<FontDescriptionRun> fontDescriptions;
237   const LayoutOptions              options;
238   CreateTextModel(data.text,
239                   textArea,
240                   fontDescriptions,
241                   options,
242                   layoutSize,
243                   textModel,
244                   metrics,
245                   false,
246                   LineWrap::WORD,
247                   false,
248                   Toolkit::DevelText::EllipsisPosition::END,
249                   0.0f, // lineSpacing
250                   0.0f  // characterSpacing
251   );
252
253   LogicalModelPtr logicalModel = textModel->mLogicalModel;
254   VisualModelPtr  visualModel  = textModel->mVisualModel;
255
256   for(unsigned int index = 0; index < data.numberOfTests; ++index)
257   {
258     const bool fetched = logicalModel->FetchBidirectionalLineInfo(data.characterIndex[index]);
259
260     if(fetched != data.fetched[index])
261     {
262       std::cout << "  Different fetched result : " << fetched << ", expected : " << data.fetched[index] << std::endl;
263       return false;
264     }
265
266     if(fetched)
267     {
268       if(logicalModel->mBidirectionalLineIndex != data.bidiLineIndex[index])
269       {
270         std::cout << "  Different bidi line index : " << logicalModel->mBidirectionalLineIndex << ", expected : " << data.bidiLineIndex << std::endl;
271         return false;
272       }
273     }
274   }
275
276   return true;
277 }
278
279 bool GetLogicalCharacterIndexTest(const GetLogicalCharacterIndexData& data)
280 {
281   std::cout << "  testing : " << data.description << std::endl;
282   // Create the model.
283   ModelPtr   textModel;
284   MetricsPtr metrics;
285   Size       layoutSize;
286
287   // Create the model with the whole text.
288   const Vector<FontDescriptionRun> fontDescriptions;
289   const LayoutOptions              options;
290   CreateTextModel(data.text,
291                   data.textArea,
292                   fontDescriptions,
293                   options,
294                   layoutSize,
295                   textModel,
296                   metrics,
297                   false,
298                   LineWrap::WORD,
299                   false,
300                   Toolkit::DevelText::EllipsisPosition::END,
301                   0.0f, // lineSpacing
302                   0.0f  // characterSpacing
303   );
304
305   LogicalModelPtr logicalModel = textModel->mLogicalModel;
306   VisualModelPtr  visualModel  = textModel->mVisualModel;
307
308   for(unsigned int index = 0u; index < data.numberOfIndices; ++index)
309   {
310     // Check the current cached bidi line index. (Check it before call the GetLogicalCharacterIndex() method )
311     if(data.cachedBidiLine[index] != logicalModel->mBidirectionalLineIndex)
312     {
313       std::cout << "  index : " << index << ", different cached bidi index : " << logicalModel->mBidirectionalLineIndex << ", expected : " << data.cachedBidiLine[index] << std::endl;
314       return false;
315     }
316
317     const bool      fetched      = logicalModel->FetchBidirectionalLineInfo(index);
318     const Character logicalIndex = fetched ? logicalModel->GetLogicalCharacterIndex(index) : index;
319
320     if(data.visualToLogical[index] != logicalIndex)
321     {
322       std::cout << "  visual index : " << index << ", different logical index : " << logicalIndex << ", expected : " << data.visualToLogical[index] << std::endl;
323       return false;
324     }
325   }
326   return true;
327 }
328
329 bool GetLogicalCursorIndexTest(const GetLogicalCursorIndexData& data)
330 {
331   tet_printf("  testing : %s\n", data.description.c_str());
332
333   // Load some fonts.
334   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
335   fontClient.SetDpi(96u, 96u);
336
337   char*             pathNamePtr = get_current_dir_name();
338   const std::string pathName(pathNamePtr);
339   free(pathNamePtr);
340
341   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf");
342   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf");
343
344   // Create the model.
345   ModelPtr   textModel;
346   MetricsPtr metrics;
347   Size       layoutSize;
348
349   // Create the model with the whole text.
350   Vector<FontDescriptionRun> fontDescriptionRuns;
351   if(0u != data.numberOfFonts)
352   {
353     fontDescriptionRuns.Insert(fontDescriptionRuns.End(),
354                                data.fontDescriptions,
355                                data.fontDescriptions + data.numberOfFonts);
356   }
357
358   const LayoutOptions options;
359   CreateTextModel(data.text,
360                   data.textArea,
361                   fontDescriptionRuns,
362                   options,
363                   layoutSize,
364                   textModel,
365                   metrics,
366                   false,
367                   LineWrap::WORD,
368                   false,
369                   Toolkit::DevelText::EllipsisPosition::END,
370                   0.0f, // lineSpacing
371                   0.0f  // characterSpacing
372   );
373
374   LogicalModelPtr logicalModel = textModel->mLogicalModel;
375   VisualModelPtr  visualModel  = textModel->mVisualModel;
376
377   for(unsigned int index = 0u; index < data.numberOfIndices; ++index)
378   {
379     const bool fetched = logicalModel->FetchBidirectionalLineInfo(data.characterIndex[index]);
380     tet_printf("  fetched %d, line index %d, expected line index %d\n", fetched, logicalModel->mBidirectionalLineIndex, data.cachedBidiLine[index]);
381
382     if(logicalModel->mBidirectionalLineIndex != data.cachedBidiLine[index])
383     {
384       tet_printf("  test : %d, different cached line index : %d, expected : %d\n", index, logicalModel->mBidirectionalLineIndex, data.cachedBidiLine[index]);
385       return false;
386     }
387
388     const CharacterIndex visualCharacterIndex = data.visualCursorIndex[index];
389     const CharacterIndex logicalCursorIndex   = fetched ? logicalModel->GetLogicalCursorIndex(visualCharacterIndex) : visualCharacterIndex;
390     tet_printf("  visual index %d, logical index %d\n", visualCharacterIndex, logicalCursorIndex);
391
392     if(logicalCursorIndex != data.logicalCursorIndex[index])
393     {
394       tet_printf("  test : %d, visual index : %d, different logical cursor index :%d, expected : %d\n", index, visualCharacterIndex, logicalCursorIndex, data.logicalCursorIndex[index]);
395       return false;
396     }
397   }
398
399   return true;
400 }
401
402 } // namespace
403
404 //////////////////////////////////////////////////////////
405 //
406 // UtcDaliCreateParagraph
407 // UtcDaliFindParagraph
408 // UtcDaliFetchBidirectionalLineInfo
409 // UtcDaliGetLogicalCharacterIndex
410 // UtcDaliGetLogicalCursorIndex
411 //
412 //////////////////////////////////////////////////////////
413
414 int UtcDaliCreateParagraph(void)
415 {
416   tet_infoline(" UtcDaliCreateParagraph");
417
418   unsigned int paragraphsIndices01[]            = {0u};
419   unsigned int paragraphsNumberOfCharacters01[] = {0u};
420   unsigned int paragraphsIndices02[]            = {0u, 12u, 17u};
421   unsigned int paragraphsNumberOfCharacters02[] = {12u, 5u, 1u};
422   unsigned int paragraphsIndices03[]            = {0u, 12u, 17u, 34u};
423   unsigned int paragraphsNumberOfCharacters03[] = {12u, 5u, 17u, 1u};
424
425   struct CreateParagraphData data[] =
426     {
427       {
428         "Zero characters",
429         "",
430         0u,
431         0u,
432         0u,
433         paragraphsIndices01,
434         paragraphsNumberOfCharacters01,
435       },
436       {
437         "Some paragraphs",
438         "Hello world\ndemo\n\n",
439         0u,
440         18u,
441         3u,
442         paragraphsIndices02,
443         paragraphsNumberOfCharacters02,
444       },
445       {
446         "Some paragraphs. Update the initial paragraphs.",
447         "Hello world\ndemo\nhello world demo\n\n",
448         0u,
449         17u,
450         4u,
451         paragraphsIndices03,
452         paragraphsNumberOfCharacters03,
453       },
454       {
455         "Some paragraphs. Update the mid paragraphs.",
456         "Hello world\ndemo\nhello world demo\n\n",
457         12u,
458         5u,
459         4u,
460         paragraphsIndices03,
461         paragraphsNumberOfCharacters03,
462       },
463       {
464         "Some paragraphs. Update the final paragraphs.",
465         "Hello world\ndemo\nhello world demo\n\n",
466         17u,
467         18u,
468         4u,
469         paragraphsIndices03,
470         paragraphsNumberOfCharacters03,
471       },
472     };
473   const unsigned int numberOfTests = 5u;
474
475   for(unsigned int index = 0u; index < numberOfTests; ++index)
476   {
477     ToolkitTestApplication application;
478     if(!CreateParagraphTest(data[index]))
479     {
480       tet_result(TET_FAIL);
481     }
482   }
483
484   tet_result(TET_PASS);
485   END_TEST;
486 }
487
488 int UtcDaliFindParagraph(void)
489 {
490   tet_infoline(" UtcDaliFindParagraph");
491
492   unsigned int paragraphs01[] = {};
493   unsigned int paragraphs02[] = {0u, 1u, 2u};
494   unsigned int paragraphs03[] = {0u};
495   unsigned int paragraphs04[] = {1u};
496   unsigned int paragraphs05[] = {0u, 1u, 2u};
497
498   struct FindParagraphData data[] =
499     {
500       {
501         "Zero characters",
502         "",
503         0u,
504         100u,
505         0u,
506         paragraphs01,
507       },
508       {"Some paragraphs",
509        "Hello world\ndemo\n\n",
510        0u,
511        18u,
512        3u,
513        paragraphs02},
514       {"Some paragraphs",
515        "Hello world\ndemo\n\n",
516        0u,
517        12u,
518        1u,
519        paragraphs03},
520       {"Some paragraphs",
521        "Hello world\ndemo\n\n",
522        12u,
523        5u,
524        1u,
525        paragraphs04},
526       {"Some paragraphs",
527        "Hello world\ndemo\n\n",
528        3u,
529        15u,
530        3u,
531        paragraphs05},
532     };
533   const unsigned int numberOfTests = 5u;
534
535   for(unsigned int index = 0u; index < numberOfTests; ++index)
536   {
537     ToolkitTestApplication application;
538     if(!FindParagraphTest(data[index]))
539     {
540       tet_result(TET_FAIL);
541     }
542   }
543
544   tet_result(TET_PASS);
545   END_TEST;
546 }
547
548 int UtcDaliFetchBidirectionalLineInfo(void)
549 {
550   tet_infoline(" UtcDaliFetchBidirectionalLineInfo");
551
552   unsigned int logicalIndex01[] = {0u};
553   bool         fetched01[]      = {false};
554   unsigned int bidiLine01[]     = {0u};
555
556   unsigned int logicalIndex02[] = {3u};
557   bool         fetched02[]      = {false};
558   unsigned int bidiLine02[]     = {0u};
559
560   unsigned int logicalIndex03[] = {0u, 11u, 12u, 21u, 22u, 33u, 34u, 43u, 44u, 54u};
561   bool         fetched03[]      = {false, false, true, true, false, false, true, true, false, false};
562   unsigned int bidiLine03[]     = {0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 0u, 0u};
563
564   struct FetchBidirectionalLineInfoData data[] =
565     {
566       {"Void text",
567        "",
568        1u,
569        logicalIndex01,
570        fetched01,
571        bidiLine01},
572       {"LTR text",
573        "Hello world",
574        1u,
575        logicalIndex02,
576        fetched02,
577        bidiLine02},
578       {"Bidi text",
579        "Hello world\nשלום עולם\nhello world\nשלום עולם\nhello world",
580        10u,
581        logicalIndex03,
582        fetched03,
583        bidiLine03}};
584   const unsigned int numberOfTests = 3u;
585
586   for(unsigned int index = 0u; index < numberOfTests; ++index)
587   {
588     ToolkitTestApplication application;
589     if(!FetchBidirectionalLineInfoTest(data[index]))
590     {
591       tet_result(TET_FAIL);
592     }
593   }
594
595   tet_result(TET_PASS);
596   END_TEST;
597 }
598
599 int UtcDaliGetLogicalCharacterIndex(void)
600 {
601   tet_infoline(" UtcDaliSetVisualToLogicalMap");
602
603   unsigned int visualToLogical01[] = {};
604   unsigned int cachedBidiLine01[]  = {};
605   unsigned int visualToLogical02[] = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u};
606   unsigned int cachedBidiLine02[]  = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
607   unsigned int visualToLogical03[] = {12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u};
608   unsigned int cachedBidiLine03[]  = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
609
610   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, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 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};
611   unsigned int cachedBidiLine04[]  = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u};
612
613   // size 300, 300
614   // LO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,   _  h  e  l  l  o  _  w  o  r  l  d \n
615   //      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
616   // VO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ل  ا  ع   ل  ا  ب  _  ا   ب  ح  ر  م  ,   _  h  e  l  l  o  _  w  o  r  l  d \n
617   //      0  1  2  3  4  5  6  7  8  9 10 11 12 25 24 23 22 21 20 19 18 17 16 15 14 13 26 27 28 29 30 31 32 33 34 35 36 37 38 39
618
619   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,  _  h  e  l  l  o  _  w  o  r  l  d   ,  _  م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
620   //     40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
621   // VO  \n  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م  _  ,  h  e  l  l  o  _  w  o  r  l  d   _  ,  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
622   //     81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 55 56 57 58 59 60 61 62 63 64 65 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
623
624   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
625   //     82 83 84 85 86 87 88 89 90 91 92 93 94 95
626   // VO  \n  م  ل  ا  ع  ل   ا  ب  _  ا   ب  ح  ر  م
627   //     95 94 93 92 91 90 89 88 87 86 85 84 83 82
628
629   // LO   h   e   l   l   o   _   w   o   r   l   d
630   //     96  97  98  99 100 101 102 103 104 105 106
631   // VO   h   e   l   l   o   _   w   o   r   l   d
632   //     96  97  98  99 100 101 102 103 104 105 106
633
634   unsigned int visualToLogical05[] = {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, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 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};
635   unsigned int cachedBidiLine05[]  = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u};
636
637   // size 300, 300
638   // LO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,   _
639   //      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
640   // VO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ل  ا  ع   ل  ا  ب  _  ا   ب  ح  ر  م  ,   _
641   //      0  1  2  3  4  5  6  7  8  9 10 11 12 25 24 23 22 21 20 19 18 17 16 15 14 13 26 27
642
643   // LO    h  e  l  l  o  _  w  o  r  l  d \n
644   //      28 29 30 31 32 33 34 35 36 37 38 39
645   // VO    h  e  l  l  o  _  w  o  r  l  d \n
646   //      28 29 30 31 32 33 34 35 36 37 38 39
647
648   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,  _  h  e  l  l  o  _  w  o  r  l  d   ,  _
649   //     40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
650   // VO  _  ,  h  e  l  l  o  _  w  o  r  l  d   _  ,  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
651   //     67 66 55 56 57 58 59 60 61 62 63 64 65 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
652
653   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
654   //     68 69 70 71 72 73 74 75 76 77 78 79 80 81
655   // VO  \n  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
656   //     81 80 79 78 77 76 75 74 73 72 71 70 69 68
657
658   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
659   //     82 83 84 85 86 87 88 89 90 91 92 93 94 95
660   // VO  \n  م  ل  ا  ع  ل   ا  ب  _  ا   ب  ح  ر  م
661   //     95 94 93 92 91 90 89 88 87 86 85 84 83 82
662
663   // LO   h   e   l   l   o   _   w   o   r   l   d
664   //     96  97  98  99 100 101 102 103 104 105 106
665   // VO   h   e   l   l   o   _   w   o   r   l   d
666   //     96  97  98  99 100 101 102 103 104 105 106
667
668   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};
669   unsigned int cachedBidiLine06[]  = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u};
670
671   // size 100, 600
672   // LO   H  e  l  l  o  _  w  o  r  l  d  ,  _
673   //      0  1  2  3  4  5  6  7  8  9 10 11 12
674   // VO   H  e  l  l  o  _  w  o  r  l  d  ,  _
675   //      0  1  2  3  4  5  6  7  8  9 10 11 12
676
677   // LO    م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,   _
678   //      13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
679   // VO    م  ل  ا  ع   ل  ا  ب  _  ا   ب  ح  ر  م  ,   _
680   //      25 24 23 22 21 20 19 18 17 16 15 14 13 26 27
681
682   // LO    h  e  l  l  o  _  w  o  r  l  d \n
683   //      28 29 30 31 32 33 34 35 36 37 38 39
684   // VO    h  e  l  l  o  _  w  o  r  l  d \n
685   //      28 29 30 31 32 33 34 35 36 37 38 39
686
687   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,  _
688   //     40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
689   // VO   _  ,  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
690   //     54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
691
692   // LO   h  e  l  l  o  _  w  o  r  l  d   ,  _
693   //     55 56 57 58 59 60 61 62 63 64 65 66 67
694   // VO   _  ,  h  e  l  l  o  _  w  o  r  l  d
695   //     67 66 55 56 57 58 59 60 61 62 63 64 65
696
697   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
698   //     68 69 70 71 72 73 74 75 76 77 78 79 80 81
699   // VO  \n  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
700   //     81 80 79 78 77 76 75 74 73 72 71 70 69 68
701
702   // LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
703   //     82 83 84 85 86 87 88 89 90 91 92 93 94 95
704   // VO  \n  م  ل  ا  ع  ل   ا  ب  _  ا   ب  ح  ر  م
705   //     95 94 93 92 91 90 89 88 87 86 85 84 83 82
706
707   // LO   h   e   l   l   o   _   w   o   r   l   d
708   //     96  97  98  99 100 101 102 103 104 105 106
709   // VO   h   e   l   l   o   _   w   o   r   l   d
710   //     96  97  98  99 100 101 102 103 104 105 106
711
712   struct GetLogicalCharacterIndexData data[] =
713     {
714       {"Zero characters text",
715        "",
716        Size(300.f, 300.f),
717        0u,
718        visualToLogical01,
719        cachedBidiLine01},
720       {"Left to right text only",
721        "Hello world",
722        Size(300.f, 300.f),
723        11u,
724        visualToLogical02,
725        cachedBidiLine02},
726       {"Right to left text only",
727        "مرحبا بالعالم",
728        Size(300.f, 300.f),
729        13u,
730        visualToLogical03,
731        cachedBidiLine03},
732       {"Mix of left to right and right to left text.",
733        "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
734        Size(300.f, 300.f),
735        107u,
736        visualToLogical04,
737        cachedBidiLine04},
738       {"Mix of left to right and right to left text.",
739        "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
740        Size(200.f, 400.f),
741        107u,
742        visualToLogical05,
743        cachedBidiLine05},
744       {"Mix of left to right and right to left text.",
745        "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
746        Size(100.f, 600.f),
747        107u,
748        visualToLogical06,
749        cachedBidiLine06},
750     };
751   const unsigned int numberOfTests = 6u;
752
753   for(unsigned int index = 0u; index < numberOfTests; ++index)
754   {
755     ToolkitTestApplication application;
756     if(!GetLogicalCharacterIndexTest(data[index]))
757     {
758       tet_result(TET_FAIL);
759     }
760   }
761
762   tet_result(TET_PASS);
763   END_TEST;
764 }
765
766 int UtcDaliGetLogicalCursorIndex(void)
767 {
768   tet_infoline(" UtcDaliGetLogicalCursorIndex");
769
770   const std::string fontFamily("TizenSans");
771   const std::string fontFamilyHebrew("TizenSansHebrew");
772
773   unsigned int visualIndex01[]            = {10u};
774   unsigned int characterIndex01[]         = {0u};
775   unsigned int logicalIndex01[]           = {10u};
776   unsigned int bidirectionalLineIndex01[] = {0u};
777
778   //  0           11
779   //   Hello world  \n
780   // 12    16
781   //   demo
782
783   // Set a known font description
784   FontDescriptionRun fontDescriptionRun02;
785   fontDescriptionRun02.characterRun.characterIndex     = 0u;
786   fontDescriptionRun02.characterRun.numberOfCharacters = 11u;
787   fontDescriptionRun02.familyLength                    = fontFamily.size();
788   fontDescriptionRun02.familyName                      = new char[fontDescriptionRun02.familyLength];
789   memcpy(fontDescriptionRun02.familyName, fontFamily.c_str(), fontDescriptionRun02.familyLength);
790   fontDescriptionRun02.familyDefined = true;
791   fontDescriptionRun02.weightDefined = false;
792   fontDescriptionRun02.widthDefined  = false;
793   fontDescriptionRun02.slantDefined  = false;
794   fontDescriptionRun02.sizeDefined   = false;
795
796   Vector<FontDescriptionRun> fontDescriptionRuns02;
797   fontDescriptionRuns02.PushBack(fontDescriptionRun02);
798
799   unsigned int visualIndex02[]            = {0u, 16u, 11u, 12u};
800   unsigned int characterIndex02[]         = {0u, 0u, 0u, 0u};
801   unsigned int logicalIndex02[]           = {0u, 16u, 11u, 12u};
802   unsigned int bidirectionalLineIndex02[] = {0u, 0u, 0u, 0u};
803
804   // LO     H  e  l  l  o  _  w  o  r  l  d  \n
805   //       0  1  2  3  4  5  6  7  8  9 10 11  12
806   // VO     H  e  l  l  o  _  w  o  r  l  d  \n
807
808   // LO         ש  ל  ו  ם  _  ע  ו  ל  ם \n
809   //          12 13 14 15 16 17 18 19 20 21  22
810   // VO     \n  ם  ל  ו  ע _  ם  ו  ל  ש
811
812   // LO      h  e  l  l  o  _  w  o  r  l  d  _  ש  ל  ו  ם  _  ע ו  ל  ם  \n
813   //       22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43  44
814   // VO      h  e  l  l  o  _  w  o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש  \n
815
816   // LO      ש  ל  ו  ם  _  ע  ו  ל  ם  _  h  e  l  l  o  _  w  o  r   l  d \n
817   //       44 45 46 47 48 49 50 51  52 52 54 55 56 57 58 59 60 61 62 63  64 65 66
818   // VO      \n h  e  l  l  o  _  w   o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש
819
820   // Set a known font description
821   FontDescriptionRun fontDescriptionRun0301;
822   fontDescriptionRun0301.characterRun.characterIndex     = 0u;
823   fontDescriptionRun0301.characterRun.numberOfCharacters = 12u;
824   fontDescriptionRun0301.familyLength                    = fontFamily.size();
825   fontDescriptionRun0301.familyName                      = new char[fontDescriptionRun0301.familyLength];
826   memcpy(fontDescriptionRun0301.familyName, fontFamily.c_str(), fontDescriptionRun0301.familyLength);
827   fontDescriptionRun0301.familyDefined = true;
828   fontDescriptionRun0301.weightDefined = false;
829   fontDescriptionRun0301.widthDefined  = false;
830   fontDescriptionRun0301.slantDefined  = false;
831   fontDescriptionRun0301.sizeDefined   = false;
832
833   // Set a known font description
834   FontDescriptionRun fontDescriptionRun0302;
835   fontDescriptionRun0302.characterRun.characterIndex     = 12u;
836   fontDescriptionRun0302.characterRun.numberOfCharacters = 10u;
837   fontDescriptionRun0302.familyLength                    = fontFamilyHebrew.size();
838   fontDescriptionRun0302.familyName                      = new char[fontDescriptionRun0302.familyLength];
839   memcpy(fontDescriptionRun0302.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0302.familyLength);
840   fontDescriptionRun0302.familyDefined = true;
841   fontDescriptionRun0302.weightDefined = false;
842   fontDescriptionRun0302.widthDefined  = false;
843   fontDescriptionRun0302.slantDefined  = false;
844   fontDescriptionRun0302.sizeDefined   = false;
845
846   // Set a known font description
847   FontDescriptionRun fontDescriptionRun0303;
848   fontDescriptionRun0303.characterRun.characterIndex     = 22u;
849   fontDescriptionRun0303.characterRun.numberOfCharacters = 12u;
850   fontDescriptionRun0303.familyLength                    = fontFamily.size();
851   fontDescriptionRun0303.familyName                      = new char[fontDescriptionRun0303.familyLength];
852   memcpy(fontDescriptionRun0303.familyName, fontFamily.c_str(), fontDescriptionRun0303.familyLength);
853   fontDescriptionRun0303.familyDefined = true;
854   fontDescriptionRun0303.weightDefined = false;
855   fontDescriptionRun0303.widthDefined  = false;
856   fontDescriptionRun0303.slantDefined  = false;
857   fontDescriptionRun0303.sizeDefined   = false;
858
859   // Set a known font description
860   FontDescriptionRun fontDescriptionRun0304;
861   fontDescriptionRun0304.characterRun.characterIndex     = 34u;
862   fontDescriptionRun0304.characterRun.numberOfCharacters = 20u;
863   fontDescriptionRun0304.familyLength                    = fontFamilyHebrew.size();
864   fontDescriptionRun0304.familyName                      = new char[fontDescriptionRun0304.familyLength];
865   memcpy(fontDescriptionRun0304.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0304.familyLength);
866   fontDescriptionRun0304.familyDefined = true;
867   fontDescriptionRun0304.weightDefined = false;
868   fontDescriptionRun0304.widthDefined  = false;
869   fontDescriptionRun0304.slantDefined  = false;
870   fontDescriptionRun0304.sizeDefined   = false;
871
872   // Set a known font description
873   FontDescriptionRun fontDescriptionRun0305;
874   fontDescriptionRun0305.characterRun.characterIndex     = 54u;
875   fontDescriptionRun0305.characterRun.numberOfCharacters = 12u;
876   fontDescriptionRun0305.familyLength                    = fontFamily.size();
877   fontDescriptionRun0305.familyName                      = new char[fontDescriptionRun0305.familyLength];
878   memcpy(fontDescriptionRun0305.familyName, fontFamily.c_str(), fontDescriptionRun0305.familyLength);
879   fontDescriptionRun0305.familyDefined = true;
880   fontDescriptionRun0305.weightDefined = false;
881   fontDescriptionRun0305.widthDefined  = false;
882   fontDescriptionRun0305.slantDefined  = false;
883   fontDescriptionRun0305.sizeDefined   = false;
884
885   Vector<FontDescriptionRun> fontDescriptionRuns03;
886   fontDescriptionRuns03.PushBack(fontDescriptionRun0301);
887   fontDescriptionRuns03.PushBack(fontDescriptionRun0302);
888   fontDescriptionRuns03.PushBack(fontDescriptionRun0303);
889   fontDescriptionRuns03.PushBack(fontDescriptionRun0304);
890   fontDescriptionRuns03.PushBack(fontDescriptionRun0305);
891
892   unsigned int visualIndex03[] = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, 41u, 42u, 43u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 66u};
893
894   unsigned int characterIndex03[] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 12u, 12u, 12u, 12u, 12u, 12u, 12u, 12u, 12u, 12u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u};
895
896   unsigned int logicalIndex03[] = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 12u, 22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 42u, 41u, 40u, 39u, 38u, 37u, 36u, 35u, 43u, 65u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u};
897
898   unsigned int bidirectionalLineIndex03[] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u};
899
900   // LO     ש  ל  ו  ם  _  ע  ו  ל  ם \n
901   //       0  1  2  3  4  5  6  7  8  9 10
902   // VO  \n ם  ל  ו  ע  _  ם  ו  ל  ש
903
904   //      h  e  l  l  o  _  w  o  r  l  d  \n
905   // LO 10 11 12 13 14 15 16 17 18 19 20 21 22
906   //      h  e  l  l  o  _  w  o  r  l  d  \n
907
908   //         ש  ל  ו  ם  _  ע  ו  ל  ם _  h  e  l  l  o  _  w  o  r  l  d  \n
909   // LO    22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
910   //     \n  h  e  l  l  o  _  w  o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש
911
912   //      h  e  l  l  o  _  w  o  r  l  d  _  ש  ל  ו  ם  _  ע  ו  ל  ם \n
913   // LO 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
914   //      h  e  l  l  o  _  w  o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש \n
915
916   // Set a known font description
917   FontDescriptionRun fontDescriptionRun0401;
918   fontDescriptionRun0401.characterRun.characterIndex     = 0u;
919   fontDescriptionRun0401.characterRun.numberOfCharacters = 10u;
920   fontDescriptionRun0401.familyLength                    = fontFamilyHebrew.size();
921   fontDescriptionRun0401.familyName                      = new char[fontDescriptionRun0401.familyLength];
922   memcpy(fontDescriptionRun0401.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0401.familyLength);
923   fontDescriptionRun0401.familyDefined = true;
924   fontDescriptionRun0401.weightDefined = false;
925   fontDescriptionRun0401.widthDefined  = false;
926   fontDescriptionRun0401.slantDefined  = false;
927   fontDescriptionRun0401.sizeDefined   = false;
928
929   FontDescriptionRun fontDescriptionRun0402;
930   fontDescriptionRun0402.characterRun.characterIndex     = 10u;
931   fontDescriptionRun0402.characterRun.numberOfCharacters = 12u;
932   fontDescriptionRun0402.familyLength                    = fontFamily.size();
933   fontDescriptionRun0402.familyName                      = new char[fontDescriptionRun0402.familyLength];
934   memcpy(fontDescriptionRun0402.familyName, fontFamily.c_str(), fontDescriptionRun0402.familyLength);
935   fontDescriptionRun0402.familyDefined = true;
936   fontDescriptionRun0402.weightDefined = false;
937   fontDescriptionRun0402.widthDefined  = false;
938   fontDescriptionRun0402.slantDefined  = false;
939   fontDescriptionRun0402.sizeDefined   = false;
940
941   FontDescriptionRun fontDescriptionRun0403;
942   fontDescriptionRun0403.characterRun.characterIndex     = 22u;
943   fontDescriptionRun0403.characterRun.numberOfCharacters = 10u;
944   fontDescriptionRun0403.familyLength                    = fontFamilyHebrew.size();
945   fontDescriptionRun0403.familyName                      = new char[fontDescriptionRun0403.familyLength];
946   memcpy(fontDescriptionRun0403.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0403.familyLength);
947   fontDescriptionRun0403.familyDefined = true;
948   fontDescriptionRun0403.weightDefined = false;
949   fontDescriptionRun0403.widthDefined  = false;
950   fontDescriptionRun0403.slantDefined  = false;
951   fontDescriptionRun0403.sizeDefined   = false;
952
953   FontDescriptionRun fontDescriptionRun0404;
954   fontDescriptionRun0404.characterRun.characterIndex     = 32u;
955   fontDescriptionRun0404.characterRun.numberOfCharacters = 24u;
956   fontDescriptionRun0404.familyLength                    = fontFamily.size();
957   fontDescriptionRun0404.familyName                      = new char[fontDescriptionRun0404.familyLength];
958   memcpy(fontDescriptionRun0404.familyName, fontFamily.c_str(), fontDescriptionRun0404.familyLength);
959   fontDescriptionRun0404.familyDefined = true;
960   fontDescriptionRun0404.weightDefined = false;
961   fontDescriptionRun0404.widthDefined  = false;
962   fontDescriptionRun0404.slantDefined  = false;
963   fontDescriptionRun0404.sizeDefined   = false;
964
965   FontDescriptionRun fontDescriptionRun0405;
966   fontDescriptionRun0405.characterRun.characterIndex     = 56u;
967   fontDescriptionRun0405.characterRun.numberOfCharacters = 10u;
968   fontDescriptionRun0405.familyLength                    = fontFamilyHebrew.size();
969   fontDescriptionRun0405.familyName                      = new char[fontDescriptionRun0405.familyLength];
970   memcpy(fontDescriptionRun0405.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0405.familyLength);
971   fontDescriptionRun0405.familyDefined = true;
972   fontDescriptionRun0405.weightDefined = false;
973   fontDescriptionRun0405.widthDefined  = false;
974   fontDescriptionRun0405.slantDefined  = false;
975   fontDescriptionRun0405.sizeDefined   = false;
976
977   Vector<FontDescriptionRun> fontDescriptionRuns04;
978   fontDescriptionRuns04.PushBack(fontDescriptionRun0401);
979   fontDescriptionRuns04.PushBack(fontDescriptionRun0402);
980   fontDescriptionRuns04.PushBack(fontDescriptionRun0403);
981   fontDescriptionRuns04.PushBack(fontDescriptionRun0404);
982   fontDescriptionRuns04.PushBack(fontDescriptionRun0405);
983
984   unsigned int visualIndex04[] = {1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 10u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, 41u, 42u, 43u, 44u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u};
985
986   unsigned int characterIndex04[] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u};
987
988   unsigned int logicalIndex04[] = {9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u, 10u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 43u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, 41u, 42u, 32u, 31u, 30u, 29u, 28u, 27u, 26u, 25u, 24u, 23u, 22u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u, 56u, 64u, 63u, 62u, 61u, 60u, 59u, 58u, 57u, 65u};
989
990   unsigned int bidirectionalLineIndex04[] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u};
991
992   // LO   A  B  C  D  E  F  G  H  I  J  K
993   //     0  1  2  3  4  5  6  7  8  9 10 11
994   // LO   L  M  N
995   //    11 12 13 14
996
997   // Set a known font description
998   FontDescriptionRun fontDescriptionRun0501;
999   fontDescriptionRun0501.characterRun.characterIndex     = 0u;
1000   fontDescriptionRun0501.characterRun.numberOfCharacters = 14u;
1001   fontDescriptionRun0501.familyLength                    = fontFamily.size();
1002   fontDescriptionRun0501.familyName                      = new char[fontDescriptionRun0501.familyLength];
1003   memcpy(fontDescriptionRun0501.familyName, fontFamily.c_str(), fontDescriptionRun0501.familyLength);
1004   fontDescriptionRun0501.familyDefined = true;
1005   fontDescriptionRun0501.weightDefined = false;
1006   fontDescriptionRun0501.widthDefined  = false;
1007   fontDescriptionRun0501.slantDefined  = false;
1008   fontDescriptionRun0501.sizeDefined   = false;
1009
1010   Vector<FontDescriptionRun> fontDescriptionRuns05;
1011   fontDescriptionRuns05.PushBack(fontDescriptionRun0501);
1012
1013   unsigned int visualIndex05[] = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u};
1014
1015   unsigned int characterIndex05[] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 11u, 11u, 11u, 11u};
1016
1017   unsigned int logicalIndex05[] = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u};
1018
1019   unsigned int bidirectionalLineIndex05[] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
1020
1021   // LO      ק  ר  א  ט  ו  ן  ם  פ  ש  ד  ג  כ
1022   //        0  1  2  3  4  5  6  7  8  9  10 11 12
1023   // VO      כ  ג  ד  ש  פ  ם  ן  ו  ט  א  ר  ק
1024
1025   // LO      ע  י  ח  ל
1026   //       12 13 14 15 16
1027   // VO      ל  ח  י  ע
1028
1029   // Set a known font description
1030   FontDescriptionRun fontDescriptionRun0601;
1031   fontDescriptionRun0601.characterRun.characterIndex     = 0u;
1032   fontDescriptionRun0601.characterRun.numberOfCharacters = 16u;
1033   fontDescriptionRun0601.familyLength                    = fontFamilyHebrew.size();
1034   fontDescriptionRun0601.familyName                      = new char[fontDescriptionRun0601.familyLength];
1035   memcpy(fontDescriptionRun0601.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0601.familyLength);
1036   fontDescriptionRun0601.familyDefined = true;
1037   fontDescriptionRun0601.weightDefined = false;
1038   fontDescriptionRun0601.widthDefined  = false;
1039   fontDescriptionRun0601.slantDefined  = false;
1040   fontDescriptionRun0601.sizeDefined   = false;
1041
1042   Vector<FontDescriptionRun> fontDescriptionRuns06;
1043   fontDescriptionRuns06.PushBack(fontDescriptionRun0601);
1044
1045   unsigned int visualIndex06[] = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 12u, 13u, 14u, 15u, 16u};
1046
1047   unsigned int characterIndex06[] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 12u, 12u, 12u, 12u, 12u};
1048
1049   unsigned int logicalIndex06[] = {12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u, 16u, 15u, 14u, 13u, 12u};
1050
1051   unsigned int bidirectionalLineIndex06[] = {
1052     0u,
1053     0u,
1054     0u,
1055     0u,
1056     0u,
1057     0u,
1058     0u,
1059     0u,
1060     0u,
1061     0u,
1062     0u,
1063     0u,
1064     0u,
1065     1u,
1066     1u,
1067     1u,
1068     1u,
1069     1u,
1070   };
1071
1072   struct GetLogicalCursorIndexData data[] =
1073     {
1074       {
1075         "Zero characters text",
1076         "",
1077         Size(300.f, 300.f),
1078         0u,
1079         nullptr,
1080         1u,
1081         visualIndex01,
1082         characterIndex01,
1083         logicalIndex01,
1084         bidirectionalLineIndex01,
1085       },
1086       {
1087         "All left to right text 01.",
1088         "Hello world\ndemo",
1089         Size(300.f, 300.f),
1090         1u,
1091         fontDescriptionRuns02.Begin(),
1092         4u,
1093         visualIndex02,
1094         characterIndex02,
1095         logicalIndex02,
1096         bidirectionalLineIndex02,
1097       },
1098       {
1099         "bidirectional text 01.",
1100         "Hello world\nשלום עולם\nhello world שלום עולם\nשלום עולם hello world\n",
1101         Size(300.f, 300.f),
1102         5u,
1103         fontDescriptionRuns03.Begin(),
1104         65u,
1105         visualIndex03,
1106         characterIndex03,
1107         logicalIndex03,
1108         bidirectionalLineIndex03,
1109       },
1110       {
1111         "bidirectional text 02.",
1112         "שלום עולם\nhello world\nשלום עולם hello world\nhello world שלום עולם\n",
1113         Size(300.f, 300.f),
1114         5u,
1115         fontDescriptionRuns04.Begin(),
1116         65u,
1117         visualIndex04,
1118         characterIndex04,
1119         logicalIndex04,
1120         bidirectionalLineIndex04,
1121       },
1122       {
1123         "long line 01.",
1124         "ABCDEFGHIJKLMN",
1125         Size(100.f, 300.f),
1126         1u,
1127         fontDescriptionRuns05.Begin(),
1128         13u,
1129         visualIndex05,
1130         characterIndex05,
1131         logicalIndex05,
1132         bidirectionalLineIndex05,
1133       },
1134       {
1135         "bidirectional text 03.",
1136         "קראטוןםפשדגכעיחל",
1137         Size(100.f, 300.f),
1138         1u,
1139         fontDescriptionRuns06.Begin(),
1140         18u,
1141         visualIndex06,
1142         characterIndex06,
1143         logicalIndex06,
1144         bidirectionalLineIndex06,
1145       },
1146     };
1147   const unsigned int numberOfTests = 6u;
1148
1149   for(unsigned int index = 0u; index < numberOfTests; ++index)
1150   {
1151     ToolkitTestApplication application;
1152     if(!GetLogicalCursorIndexTest(data[index]))
1153     {
1154       tet_printf("Test %d failed : [%s]\n", index, data[index].description.c_str());
1155       tet_result(TET_FAIL);
1156     }
1157   }
1158
1159   tet_result(TET_PASS);
1160   END_TEST;
1161 }