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