[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / utc-Dali-Text-Cursor.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/cursor-helper-functions.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 // LineIndex GetClosestLine( VisualModelPtr visualModel,
34 //                           float visualY,
35 //                           bool& isLineHit )
36 // CharacterIndex GetClosestCursorIndex( VisualModelPtr visualModel,
37 //                                       LogicalModelPtr logicalModel,
38 //                                       MetricsPtr metrics,
39 //                                       float visualX,
40 //                                       float visualY,
41 //                                       CharacterHitTest::Mode mode,
42 //                                       bool& isCharacterHit )
43
44 //////////////////////////////////////////////////////////
45
46 namespace
47 {
48 const std::string  DEFAULT_FONT_DIR("/resources/fonts");
49 const unsigned int DEFAULT_FONT_SIZE = 1152u;
50
51 struct GetClosestLineData
52 {
53   std::string  description;   ///< Description of the test.
54   std::string  text;          ///< Input text.
55   unsigned int numberOfTests; ///< The number of tests.
56   float*       visualY;       ///< The visual 'y' position for each test.
57   LineIndex*   lineIndex;     ///< The expected line index for each test.
58   bool*        isLineHit;     ///< The expected line hit value for each test.
59 };
60
61 struct GetClosestCursorIndexData
62 {
63   std::string             description;            ///< Description of the test.
64   std::string             text;                   ///< Input text.
65   unsigned int            numberOfTests;          ///< The number of tests.
66   float*                  visualX;                ///< The visual 'x' position for each test.
67   float*                  visualY;                ///< The visual 'y' position for each test.
68   CharacterHitTest::Mode* mode;                   ///< The type of hit test.
69   bool                    markupProcessorEnabled; //< Enable markup processor to use markup text.
70   CharacterIndex*         logicalIndex;           ///< The expected logical cursor index for each test.
71   bool*                   isCharacterHit;         ///< The expected character hit value for each test.
72 };
73
74 struct GetCursorPositionData
75 {
76   std::string     description;   ///< Description of the test.
77   std::string     text;          ///< Input text.
78   unsigned int    numberOfTests; ///< The number of tests.
79   CharacterIndex* logicalIndex;  ///< The logical cursor index for each test.
80   float*          visualX;       ///< The expected visual 'x' position for each test.
81   float*          visualY;       ///< The expected visual 'y' position for each test.
82 };
83
84 struct FindSelectionIndicesData
85 {
86   std::string     description;    ///< Description of the test.
87   std::string     text;           ///< Input text.
88   unsigned int    numberOfTests;  ///< The number of tests.
89   float*          visualX;        ///< The visual 'x' position for each test.
90   float*          visualY;        ///< The visual 'y' position for each test.
91   bool*           found;          ///< Whether selection indices are found.
92   CharacterIndex* startIndex;     ///< The expected start cursor index for each test.
93   CharacterIndex* endIndex;       ///< The expected end cursor index for each test.
94   CharacterIndex* noTextHitIndex; ///< The expected character index when there is no hit.
95 };
96
97 struct PrimaryCursorHeightData
98 {
99   std::string     description;   ///< Description of the test.
100   std::string     text;          ///< Input text.
101   unsigned int    numberOfTests; ///< The number of tests.
102   CharacterIndex* logicalIndex;  ///< The logical cursor index for each test.
103   float*          heights;       ///< The expected primary cursor height for each test.
104 };
105
106 bool GetClosestLineTest(const GetClosestLineData& data)
107 {
108   std::cout << "  testing : " << data.description << std::endl;
109
110   // 1) Create the model.
111   ModelPtr   textModel;
112   MetricsPtr metrics;
113   Size       textArea(400.f, 600.f);
114   Size       layoutSize;
115
116   Vector<FontDescriptionRun> fontDescriptionRuns;
117   LayoutOptions              options;
118   CreateTextModel(data.text,
119                   textArea,
120                   fontDescriptionRuns,
121                   options,
122                   layoutSize,
123                   textModel,
124                   metrics,
125                   false,
126                   LineWrap::WORD,
127                   false,
128                   Toolkit::DevelText::EllipsisPosition::END,
129                   0.0f, // lineSpacing
130                   0.0f  // characterSpacing
131   );
132
133   LogicalModelPtr logicalModel = textModel->mLogicalModel;
134   VisualModelPtr  visualModel  = textModel->mVisualModel;
135
136   for(unsigned int index = 0; index < data.numberOfTests; ++index)
137   {
138     bool            isLineHit = false;
139     const LineIndex lineIndex = GetClosestLine(visualModel,
140                                                data.visualY[index],
141                                                isLineHit);
142
143     if(lineIndex != data.lineIndex[index])
144     {
145       std::cout << "  test " << index << " failed. Different line index : " << lineIndex << ", expected : " << data.lineIndex[index] << std::endl;
146       return false;
147     }
148     if(isLineHit != data.isLineHit[index])
149     {
150       std::cout << "  test " << index << " failed. Different line hit value : " << isLineHit << ", expected : " << data.isLineHit[index] << std::endl;
151       return false;
152     }
153   }
154
155   return true;
156 }
157
158 bool GetClosestCursorIndexTest(const GetClosestCursorIndexData& data)
159 {
160   std::cout << "  testing : " << data.description << std::endl;
161
162   // 1) Create the model.
163   ModelPtr   textModel;
164   MetricsPtr metrics;
165   Size       textArea(400.f, 600.f);
166   Size       layoutSize;
167
168   Vector<FontDescriptionRun> fontDescriptionRuns;
169   LayoutOptions              options;
170   CreateTextModel(data.text,
171                   textArea,
172                   fontDescriptionRuns,
173                   options,
174                   layoutSize,
175                   textModel,
176                   metrics,
177                   data.markupProcessorEnabled,
178                   LineWrap::WORD,
179                   false,
180                   Toolkit::DevelText::EllipsisPosition::END,
181                   0.0f, // lineSpacing
182                   0.0f  // characterSpacing
183   );
184
185   LogicalModelPtr logicalModel = textModel->mLogicalModel;
186   VisualModelPtr  visualModel  = textModel->mVisualModel;
187
188   for(unsigned int index = 0; index < data.numberOfTests; ++index)
189   {
190     bool                 isCharacterHit     = false;
191     const CharacterIndex logicalCursorIndex = GetClosestCursorIndex(visualModel,
192                                                                     logicalModel,
193                                                                     metrics,
194                                                                     data.visualX[index],
195                                                                     data.visualY[index],
196                                                                     data.mode[index],
197                                                                     isCharacterHit);
198     if(logicalCursorIndex != data.logicalIndex[index])
199     {
200       std::cout << "  test " << index << " failed. Different logical cursor index : " << logicalCursorIndex << ", expected : " << data.logicalIndex[index] << std::endl;
201       return false;
202     }
203     if(isCharacterHit != data.isCharacterHit[index])
204     {
205       std::cout << "  test " << index << " failed. Different character hit value : " << isCharacterHit << ", expected : " << data.isCharacterHit[index] << std::endl;
206       return false;
207     }
208   }
209
210   return true;
211 }
212
213 bool GetCursorPositionTest(const GetCursorPositionData& data)
214 {
215   std::cout << "  testing : " << data.description << std::endl;
216
217   // 1) Create the model.
218   ModelPtr   textModel;
219   MetricsPtr metrics;
220   Size       textArea(400.f, 600.f);
221   Size       layoutSize;
222
223   Vector<FontDescriptionRun> fontDescriptionRuns;
224   LayoutOptions              options;
225   CreateTextModel(data.text,
226                   textArea,
227                   fontDescriptionRuns,
228                   options,
229                   layoutSize,
230                   textModel,
231                   metrics,
232                   false,
233                   LineWrap::WORD,
234                   false,
235                   Toolkit::DevelText::EllipsisPosition::END,
236                   0.0f, // lineSpacing
237                   0.0f  // characterSpacing
238   );
239
240   LogicalModelPtr logicalModel = textModel->mLogicalModel;
241   VisualModelPtr  visualModel  = textModel->mVisualModel;
242
243   GetCursorPositionParameters parameters;
244   parameters.visualModel  = visualModel;
245   parameters.logicalModel = logicalModel;
246   parameters.metrics      = metrics;
247   parameters.isMultiline  = true;
248
249   for(unsigned int index = 0; index < data.numberOfTests; ++index)
250   {
251     CursorInfo cursorInfo;
252     parameters.logical = data.logicalIndex[index];
253
254     GetCursorPosition(parameters,
255                       0.f, // Since this test case is not testing the primary cursor height, the default font line height can be set to 0.f.
256                       cursorInfo);
257
258     if(floor(cursorInfo.primaryPosition.x) != data.visualX[index])
259     {
260       std::cout << "  test " << index << " failed. Different 'x' cursor position : " << cursorInfo.primaryPosition.x << ", expected : " << data.visualX[index] << std::endl;
261       return false;
262     }
263     if(floor(cursorInfo.primaryPosition.y) != data.visualY[index])
264     {
265       std::cout << "  test " << index << " failed. Different 'y' cursor position : " << cursorInfo.primaryPosition.y << ", expected : " << data.visualY[index] << std::endl;
266       return false;
267     }
268   }
269
270   return true;
271 }
272
273 bool FindSelectionIndicesTest(const FindSelectionIndicesData& data)
274 {
275   std::cout << "  testing : " << data.description << std::endl;
276
277   // 1) Create the model.
278   ModelPtr   textModel;
279   MetricsPtr metrics;
280   Size       textArea(400.f, 600.f);
281   Size       layoutSize;
282
283   Vector<FontDescriptionRun> fontDescriptionRuns;
284   LayoutOptions              options;
285   CreateTextModel(data.text,
286                   textArea,
287                   fontDescriptionRuns,
288                   options,
289                   layoutSize,
290                   textModel,
291                   metrics,
292                   false,
293                   LineWrap::WORD,
294                   false,
295                   Toolkit::DevelText::EllipsisPosition::END,
296                   0.0f, // lineSpacing
297                   0.0f  // characterSpacing
298   );
299
300   LogicalModelPtr logicalModel = textModel->mLogicalModel;
301   VisualModelPtr  visualModel  = textModel->mVisualModel;
302
303   for(unsigned int index = 0; index < data.numberOfTests; ++index)
304   {
305     CharacterIndex startIndex     = 0;
306     CharacterIndex endIndex       = 0;
307     CharacterIndex noTextHitIndex = 0;
308     const bool     found          = FindSelectionIndices(visualModel,
309                                             logicalModel,
310                                             metrics,
311                                             data.visualX[index],
312                                             data.visualY[index],
313                                             startIndex,
314                                             endIndex,
315                                             noTextHitIndex);
316
317     if(found != data.found[index])
318     {
319       std::cout << "  test " << index << " failed. Different found value : " << found << ", expected : " << data.found[index] << std::endl;
320       return false;
321     }
322     if(startIndex != data.startIndex[index])
323     {
324       std::cout << "  test " << index << " failed. Different start index : " << startIndex << ", expected : " << data.startIndex[index] << std::endl;
325       return false;
326     }
327     if(endIndex != data.endIndex[index])
328     {
329       std::cout << "  test " << index << " failed. Different end index : " << endIndex << ", expected : " << data.endIndex[index] << std::endl;
330       return false;
331     }
332     if(noTextHitIndex != data.noTextHitIndex[index])
333     {
334       std::cout << "  test " << index << " failed. Different no text hit index : " << noTextHitIndex << ", expected : " << data.noTextHitIndex[index] << std::endl;
335       return false;
336     }
337   }
338   return true;
339 }
340
341 bool PrimaryCursorHeightTest(const PrimaryCursorHeightData& data)
342 {
343   std::cout << "  testing : " << data.description << std::endl;
344
345   // 1) Create the model.
346   ModelPtr   textModel;
347   MetricsPtr metrics;
348   Size       textArea(400.f, 600.f);
349   Size       layoutSize;
350
351   Vector<FontDescriptionRun> fontDescriptionRuns;
352
353   const std::string fontFamily("DejaVuSans");
354
355   // Set a known font description
356   FontDescriptionRun fontDescriptionRun1;
357   fontDescriptionRun1.characterRun.characterIndex     = 0u;
358   fontDescriptionRun1.characterRun.numberOfCharacters = 13u;
359   fontDescriptionRun1.familyLength                    = fontFamily.size();
360   fontDescriptionRun1.familyName                      = new char[fontDescriptionRun1.familyLength];
361   memcpy(fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength);
362   fontDescriptionRun1.familyDefined = true;
363   fontDescriptionRun1.weightDefined = false;
364   fontDescriptionRun1.widthDefined  = false;
365   fontDescriptionRun1.slantDefined  = false;
366   fontDescriptionRun1.sizeDefined   = true;
367   fontDescriptionRun1.size          = 768u; //Font size = 12.0f (768/64 = 12)
368
369   fontDescriptionRuns.PushBack(fontDescriptionRun1);
370
371   LayoutOptions options;
372   CreateTextModel(data.text,
373                   textArea,
374                   fontDescriptionRuns,
375                   options,
376                   layoutSize,
377                   textModel,
378                   metrics,
379                   false,
380                   LineWrap::WORD,
381                   false,
382                   Toolkit::DevelText::EllipsisPosition::END,
383                   50.0f, // lineSpacing
384                   50.0f  // characterSpacing
385   );
386
387   LogicalModelPtr logicalModel = textModel->mLogicalModel;
388   VisualModelPtr  visualModel  = textModel->mVisualModel;
389
390   GetCursorPositionParameters parameters;
391   parameters.visualModel  = visualModel;
392   parameters.logicalModel = logicalModel;
393   parameters.metrics      = metrics;
394   parameters.isMultiline  = true;
395
396   for(unsigned int index = 0; index < data.numberOfTests; ++index)
397   {
398     CursorInfo cursorInfo;
399     parameters.logical = data.logicalIndex[index];
400
401     // Load some fonts.
402     TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
403     fontClient.SetDpi(93u, 93u);
404
405     char*             pathNamePtr = get_current_dir_name();
406     const std::string pathName(pathNamePtr);
407     free(pathNamePtr);
408
409     FontId fontID = fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSans.ttf");
410
411     Text::FontMetrics fontMetrics;
412     MetricsPtr        mMetrics = Metrics::New(fontClient);
413     mMetrics->GetFontMetrics(fontID, fontMetrics);
414     float defaultFontLineHeight = (fontMetrics.ascender - fontMetrics.descender);
415
416     GetCursorPosition(parameters,
417                       defaultFontLineHeight,
418                       cursorInfo);
419
420     if(floor(cursorInfo.primaryCursorHeight) != data.heights[index])
421     {
422       std::cout << "  test " << index << " failed. Different primaryCursorHeight : " << cursorInfo.primaryCursorHeight << ", expected : " << data.heights[index] << std::endl;
423       return false;
424     }
425   }
426
427   return true;
428 }
429
430 } // namespace
431
432 //////////////////////////////////////////////////////////
433 //
434 // UtcDaliGetClosestLine
435 // UtcDaliGetClosestCursorIndex
436 // UtcDaliGetCursorPosition
437 // UtcDaliFindSelectionIndices
438 // UtcDaliPrimaryCursorHeight
439 //
440 //////////////////////////////////////////////////////////
441
442 int UtcDaliGetClosestLine(void)
443 {
444   tet_infoline(" UtcDaliGetClosestLine");
445
446   float     visualY01[]     = {-4.f, 3.f, 1000.f};
447   LineIndex lineIndices01[] = {0, 0, 0};
448   bool      isLineHit01[]   = {false, false, false};
449
450   float     visualY02[]     = {-4.f, 3.f, 1000.f};
451   LineIndex lineIndices02[] = {0, 0, 0};
452   bool      isLineHit02[]   = {false, true, false};
453
454   float     visualY03[]     = {-4.f, 11.f, 30.f, 51.f, 68.f, 87.f, 109.f, 130.f};
455   LineIndex lineIndices03[] = {0, 0, 1u, 2u, 3u, 4u, 5u, 5u};
456   bool      isLineHit03[]   = {false, true, true, true, true, true, true, false};
457
458   struct GetClosestLineData data[] =
459     {
460       {"void text.",
461        "",
462        3u,
463        visualY01,
464        lineIndices01,
465        isLineHit01},
466       {"Single line text.",
467        "hello world",
468        3u,
469        visualY02,
470        lineIndices02,
471        isLineHit02},
472       {"Multi-line text.",
473        "abcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuדאוvwxה"
474        "סתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuד"
475        "אוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqr"
476        "פרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmno"
477        "צמםpqrפרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjkl"
478        "חלךmnoצמםpqrפרףstuדאוvwxהסתyzטזץ",
479        8u,
480        visualY03,
481        lineIndices03,
482        isLineHit03}};
483   const unsigned int numberOfTests = 3u;
484
485   for(unsigned int index = 0; index < numberOfTests; ++index)
486   {
487     ToolkitTestApplication application;
488     if(!GetClosestLineTest(data[index]))
489     {
490       tet_result(TET_FAIL);
491     }
492   }
493
494   tet_result(TET_PASS);
495   END_TEST;
496 }
497
498 int UtcDaliGetClosestCursorIndex(void)
499 {
500   tet_infoline(" UtcDaliGetClosestCursorIndex");
501
502   float                  visualX01[]        = {-100.f};
503   float                  visualY01[]        = {-100.f};
504   CharacterHitTest::Mode mode01[]           = {CharacterHitTest::TAP};
505   CharacterIndex         logicalIndex01[]   = {0};
506   bool                   isCharacterHit01[] = {false};
507
508   float                  visualX02[]        = {-100.f, 1000.f, 60.f, 79.f, 83.f, 148.f, 99.f};
509   float                  visualY02[]        = {-100.f, 1000.f, 12.f, 12.f, 12.f, 12.f, 12.f};
510   CharacterHitTest::Mode mode02[]           = {CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP};
511   CharacterIndex         logicalIndex02[]   = {0, 21u, 7u, 10u, 11u, 14u, 20u};
512   bool                   isCharacterHit02[] = {false, false, true, true, true, true, true};
513
514   float                  visualX03[]        = {19.f, 104.f, -2.f, 127.f};
515   float                  visualY03[]        = {12.f, 12.f, 12.f, 12.f};
516   CharacterHitTest::Mode mode03[]           = {CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP};
517   CharacterIndex         logicalIndex03[]   = {3u, 13u, 0, 18u};
518   bool                   isCharacterHit03[] = {true, true, false, false};
519
520   //  0     5 _ 6     11  12
521   //   Hello     world  \n
522   // 12    16 _ 17    21   22
523   //   שלום       עולם  \n
524   // 22         31_32      40  41
525   //   different     الأربعاء  \n
526   float                  visualX04[]        = {-100.f, 40.f, 44.f, 85.f, 500.f, 500.f, 367.f, 359.f, 329.f, -100.f, -100.f, 19.f, 64.f, 72.f, 104.f, 111.f, 500.f};
527   float                  visualY04[]        = {-100.f, 12.f, 12.f, 12.f, 12.f, 30.f, 30.f, 30.f, 30.f, 30.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f};
528   CharacterHitTest::Mode mode04[]           = {CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP};
529   CharacterIndex         logicalIndex04[]   = {0, 5u, 6u, 11u, 11u, 12u, 16u, 17u, 21u, 21u, 22u, 25u, 31u, 32u, 35u, 34u, 40u, 41u};
530   bool                   isCharacterHit04[] = {false, true, true, true, false, false, true, true, true, false, false, true, true, true, true, true, false};
531
532   //   0           10           20            30           40      46
533   //    abcשנבdefג   קכghiעיןjk   lחלךmnoצמם   pqrפרףstuד   אוvwxה
534   //  46     50            60            70           80               93
535   //    סתyz   טזץabcשנבd    efגקכghiעי    ןjklחלךmno   צמםpqrפרףstuד
536   //  93       100           110          120         130          139
537   //    אוvwxהס   תyzטזץabcש   נבdefגקכgh   iעיןjklחלך   mnoצמםpqr
538   // 139           150           160           170          180       186
539   //    פרףstuדאוvw   xהסתyzטזץa   bcשנבdefגק    כghiעיןjkl    חלךmno
540   // 186     190           200           210          220            233
541   //    צמםp   qrפרףstuדא    וvwxהסתyzט   זץabcשנבde   fגקכghiעיןjkl
542   // 233        240            250           260     265
543   //    חלךmnoצ    מםpqrפרףst   uדאוvwxהסת    yzטזץ
544
545   float                  visualX05[]        = {-100.f, 96.f, 155.f, 250.f, 344.f, 500.f, -100.f, 36.f, 124.f, 190.f, 280.f, 500.f, -100.f, 56.f, 158.f, 237.f, 303.f, 500.f, -100.f, 98.f, 184.f, 261.f, 337.f, 500.f, -100.f, 40.f, 113.f, 223.f, 302.f, 500.f, -100.f, 82.f, 160.f, 253.f, 500.f};
546   float                  visualY05[]        = {-100.f, 12.f, 12.f, 12.f, 12.f, 12.f, 30.f, 30.f, 30.f, 30.f, 30.f, 30.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 67.f, 67.f, 67.f, 67.f, 67.f, 67.f, 87.f, 87.f, 87.f, 87.f, 87.f, 87.f, 107.f, 107.f, 107.f, 107.f, 107.f};
547   CharacterHitTest::Mode mode05[]           = {CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP};
548   CharacterIndex         logicalIndex05[]   = {0, 10u, 19u, 28u, 41u, 44u, 45u, 49u, 59u, 66u, 78u, 89u, 90u, 97u, 107u, 117u, 126u, 134u, 135u, 147u, 155u, 163u, 172u, 180u, 181u, 185u, 192u, 204u, 213u, 222u, 223u, 234u, 242u, 252u, 265u};
549   bool                   isCharacterHit05[] = {false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, false};
550
551   //   0            10           20           30           40        46
552   //    שנבabcגקכd    efעיןghiחל   ךjklצמםmno   פרףpqrדאוs   tuהסתv
553   //  46     50           60          70            80              93
554   //    wxטז   ץyzשנבabcג   קכdefעיןgh   iחלךjklצמם   mnoפרףpqrדאוs
555   //  93        100          110          120           130           139
556   //    tuהסתvw   xטזץyzשנבa   bcגקכdefעי    ןghiחלךjkl    צמםmnoפרף
557   // 139           150           160          170         180       186
558   //    pqrדאוstuהס   תvwxטזץyzש   נבabcגקכde   fעיןghiחלך   jklצמם
559   // 186    190          200           210           220            232
560   //    mnoפ   רףpqrדאוst   uהסתvwxטזץ   yzשנבabcגק    כdefעיןghiחל
561   // 232         240           250           260     265
562   //    ךjklצמםm   noפרףpqrדא    וstuהסתvwx   טזץyz
563
564   float                  visualX06[]        = {500.f, 307.f, 237.f, 148.f, 55.f, -100.f, 500.f, 362.f, 276.f, 213.f, 121.f, -100.f, 500.f, 344.f, 238.f, 167.f, 93.f, -100.f, 500.f, 306.f, 216.f, 142.f, 58.f, -100.f, 500.f, 355.f, 279.f, 182.f, 92.f, -100.f, 500.f, 326.f, 238.f, 150.f, -100.f};
565   float                  visualY06[]        = {-100.f, 12.f, 12.f, 12.f, 12.f, 12.f, 30.f, 30.f, 30.f, 30.f, 30.f, 30.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 67.f, 67.f, 67.f, 67.f, 67.f, 67.f, 87.f, 87.f, 87.f, 87.f, 87.f, 87.f, 107.f, 107.f, 107.f, 107.f, 107.f};
566   CharacterHitTest::Mode mode06[]           = {CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP};
567   CharacterIndex         logicalIndex06[]   = {0, 10u, 19u, 28u, 39u, 44u, 45u, 49u, 59u, 66u, 78u, 89u, 90u, 97u, 108u, 117u, 126u, 134u, 135u, 145u, 155u, 163u, 174u, 180u, 181u, 186u, 194u, 204u, 214u, 222u, 224u, 235u, 243u, 252u, 265u};
568   bool                   isCharacterHit06[] = {false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, true, false, false, true, true, true, false};
569
570   float                  visualX07[]        = {395.f};
571   float                  visualY07[]        = {12.f};
572   CharacterHitTest::Mode mode07[]           = {CharacterHitTest::TAP};
573   CharacterIndex         logicalIndex07[]   = {1u};
574   bool                   isCharacterHit07[] = {true};
575
576   float                  visualX08[]        = {7.f};
577   float                  visualY08[]        = {12.f};
578   CharacterHitTest::Mode mode08[]           = {CharacterHitTest::TAP};
579   CharacterIndex         logicalIndex08[]   = {1u};
580   bool                   isCharacterHit08[] = {true};
581
582   float                  visualX09[]        = {9.f};
583   float                  visualY09[]        = {12.f};
584   CharacterHitTest::Mode mode09[]           = {CharacterHitTest::TAP};
585   CharacterIndex         logicalIndex09[]   = {1u};
586   bool                   isCharacterHit09[] = {true};
587
588   struct GetClosestCursorIndexData data[] =
589     {
590       {"Void text.",
591        "",
592        1u,
593        visualX01,
594        visualY01,
595        mode01,
596        false,
597        logicalIndex01,
598        isCharacterHit01},
599
600       {"Single line text.",
601        "Hello world שלום עולם",
602        7u,
603        visualX02,
604        visualY02,
605        mode02,
606        false,
607        logicalIndex02,
608        isCharacterHit02},
609
610       {"Single line with ligatures",
611        "different الأربعاء",
612        4u,
613        visualX03,
614        visualY03,
615        mode03,
616        false,
617        logicalIndex03,
618        isCharacterHit03},
619
620       {"Multiline. Single line paragraphs",
621        "Hello world\n"
622        "שלום עולם\n"
623        "different الأربعاء\n",
624        17u,
625        visualX04,
626        visualY04,
627        mode04,
628        false,
629        logicalIndex04,
630        isCharacterHit04},
631
632       {"Multiline. Single bidirectional paragraph, starts LTR, wrapped lines",
633        "abcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuדאוvwxה"
634        "סתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuד"
635        "אוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqr"
636        "פרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmno"
637        "צמםpqrפרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjkl"
638        "חלךmnoצמםpqrפרףstuדאוvwxהסתyzטזץ",
639        35u,
640        visualX05,
641        visualY05,
642        mode05,
643        false,
644        logicalIndex05,
645        isCharacterHit05},
646
647       {"Multiline. Single bidirectional paragraph, starts RTL, wrapped lines",
648        "שנבabcגקכdefעיןghiחלךjklצמםmnoפרףpqrדאוstuהסתv"
649        "wxטזץyzשנבabcגקכdefעיןghiחלךjklצמםmnoפרףpqrדאוs"
650        "tuהסתvwxטזץyzשנבabcגקכdefעיןghiחלךjklצמםmnoפרף"
651        "pqrדאוstuהסתvwxטזץyzשנבabcגקכdefעיןghiחלךjklצמם"
652        "mnoפרףpqrדאוstuהסתvwxטזץyzשנבabcגקכdefעיןghiחל"
653        "ךjklצמםmnoפרףpqrדאוstuהסתvwxטזץyz",
654        35u,
655        visualX06,
656        visualY06,
657        mode06,
658        false,
659        logicalIndex06,
660        isCharacterHit06},
661
662       {"Testing complex characters. Arabic ligatures",
663        "الأَبْجَدِيَّة العَرَبِيَّة",
664        1u,
665        visualX07,
666        visualY07,
667        mode07,
668        false,
669        logicalIndex07,
670        isCharacterHit07},
671
672       {"Testing complex characters. Latin ligatures",
673        "fi ligature",
674        1u,
675        visualX08,
676        visualY08,
677        mode08,
678        false,
679        logicalIndex08,
680        isCharacterHit08},
681
682       {"Testing complex characters. Emoji",
683        "A&#x1F468;&#x200D;&#x1F469;&#x200D;&#x1F467;&#x200D;&#x1F466;B",
684        1u,
685        visualX09,
686        visualY09,
687        mode09,
688        true,
689        logicalIndex09,
690        isCharacterHit09}
691
692     };
693   const unsigned int numberOfTests = 9u;
694
695   for(unsigned int index = 0; index < numberOfTests; ++index)
696   {
697     ToolkitTestApplication application;
698     if(!GetClosestCursorIndexTest(data[index]))
699     {
700       tet_result(TET_FAIL);
701     }
702   }
703
704   tet_result(TET_PASS);
705   END_TEST;
706 }
707
708 int UtcDaliGetCursorPosition(void)
709 {
710   tet_infoline(" UtcDaliGetCursorPosition");
711
712   float          visualX08[]      = {5.f};
713   float          visualY08[]      = {0.f};
714   CharacterIndex logicalIndex08[] = {1u};
715
716   struct GetCursorPositionData data[] =
717     {
718       {
719         "Testing complex characters. Latin ligatures",
720         "fi ligature",
721         1u,
722         logicalIndex08,
723         visualX08,
724         visualY08,
725       }};
726   const unsigned int numberOfTests = 1u;
727
728   for(unsigned int index = 0; index < numberOfTests; ++index)
729   {
730     ToolkitTestApplication application;
731     if(!GetCursorPositionTest(data[index]))
732     {
733       tet_result(TET_FAIL);
734     }
735   }
736
737   tet_result(TET_PASS);
738   END_TEST;
739 }
740
741 int UtcDaliFindSelectionIndices(void)
742 {
743   tet_infoline(" UtcDaliFindSelectionIndices");
744
745   float          visualX01[]    = {-100.f};
746   float          visualY01[]    = {-100.f};
747   bool           found01[]      = {false};
748   CharacterIndex startIndex01[] = {0};
749   CharacterIndex endIndex01[]   = {0};
750   CharacterIndex noHitText01[]  = {0};
751
752   float          visualX02[]    = {-100.f, 1000.f, 1000.f};
753   float          visualY02[]    = {-100.f, 12.f, 1000.f};
754   bool           found02[]      = {false, false, false};
755   CharacterIndex startIndex02[] = {0, 6u, 6u};
756   CharacterIndex endIndex02[]   = {5u, 11u, 11u};
757   CharacterIndex noHitText02[]  = {0, 11u, 11u};
758
759   float          visualX03[]    = {70.f};
760   float          visualY03[]    = {12.f};
761   bool           found03[]      = {true};
762   CharacterIndex startIndex03[] = {6u};
763   CharacterIndex endIndex03[]   = {11u};
764   CharacterIndex noHitText03[]  = {0u};
765
766   float          visualX04[]    = {131.f};
767   float          visualY04[]    = {12.f};
768   bool           found04[]      = {true};
769   CharacterIndex startIndex04[] = {12u};
770   CharacterIndex endIndex04[]   = {16u};
771   CharacterIndex noHitText04[]  = {0u};
772
773   float          visualX05[]    = {0.f};
774   float          visualY05[]    = {12.f};
775   bool           found05[]      = {true};
776   CharacterIndex startIndex05[] = {0};
777   CharacterIndex endIndex05[]   = {1u};
778   CharacterIndex noHitText05[]  = {0};
779
780   float          visualX06[]    = {10.f};
781   float          visualY06[]    = {12.f};
782   bool           found06[]      = {true};
783   CharacterIndex startIndex06[] = {0};
784   CharacterIndex endIndex06[]   = {1u};
785   CharacterIndex noHitText06[]  = {0u};
786
787   struct FindSelectionIndicesData data[] =
788     {
789       {"void text",
790        "",
791        1u,
792        visualX01,
793        visualY01,
794        found01,
795        startIndex01,
796        endIndex01,
797        noHitText01},
798       {"touch out of text's boundaries",
799        "Hello world",
800        3u,
801        visualX02,
802        visualY02,
803        found02,
804        startIndex02,
805        endIndex02,
806        noHitText02},
807       {"touch on the text",
808        "Hello world demo",
809        1u,
810        visualX03,
811        visualY03,
812        found03,
813        startIndex03,
814        endIndex03,
815        noHitText03},
816       {"touch on the new paragraph character at the end of line",
817        "Hello world demo\n",
818        1u,
819        visualX04,
820        visualY04,
821        found04,
822        startIndex04,
823        endIndex04,
824        noHitText04},
825       {"touch on a white space character. is the unique character of the line",
826        " ",
827        1u,
828        visualX05,
829        visualY05,
830        found05,
831        startIndex05,
832        endIndex05,
833        noHitText05},
834       {"touch on a white space character. is between two words",
835        "h ello",
836        1u,
837        visualX06,
838        visualY06,
839        found06,
840        startIndex06,
841        endIndex06,
842        noHitText06},
843     };
844   const unsigned int numberOfTests = 6u;
845
846   for(unsigned int index = 0; index < numberOfTests; ++index)
847   {
848     ToolkitTestApplication application;
849     if(!FindSelectionIndicesTest(data[index]))
850     {
851       tet_result(TET_FAIL);
852     }
853   }
854
855   tet_result(TET_PASS);
856   END_TEST;
857 }
858
859 int UtcDaliPrimaryCursorHeight(void)
860 {
861   tet_infoline(" UtcDaliPrimaryCursorHeight");
862
863   float          heights[]      = {19.f};
864   CharacterIndex logicalIndex[] = {1u};
865
866   struct PrimaryCursorHeightData data[] =
867     {
868       {
869         "Testing primary cursor height when line spacing is used.",
870         "Hello World",
871         1u,
872         logicalIndex,
873         heights,
874       }};
875   const unsigned int numberOfTests = 1u;
876
877   for(unsigned int index = 0; index < numberOfTests; ++index)
878   {
879     ToolkitTestApplication application;
880     if(!PrimaryCursorHeightTest(data[index]))
881     {
882       tet_result(TET_FAIL);
883     }
884   }
885
886   tet_result(TET_PASS);
887   END_TEST;
888 }