Support Markup Underline attributes
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / utc-Dali-TextEditor-internal.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 <iostream>
20
21 #include <dali-toolkit-test-suite-utils.h>
22 #include <dali-toolkit/dali-toolkit.h>
23
24 #include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
25 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
26 #include <dali-toolkit/internal/text/text-controller-impl.h>
27 #include <dali-toolkit/internal/text/text-controller.h>
28
29 using namespace Dali;
30 using namespace Toolkit;
31 using namespace Text;
32
33 int UtcDaliTextEditorSelectText(void)
34 {
35   ToolkitTestApplication application;
36   tet_infoline("UtcDaliTextEditorSelectText");
37
38   // Create a text editor
39   TextEditor textEditor = TextEditor::New();
40   textEditor.SetProperty(Actor::Property::SIZE, Vector2(400.f, 60.f));
41   textEditor.SetProperty(TextEditor::Property::TEXT, "Hello World");
42
43   // Add the text editor to the stage
44   application.GetScene().Add(textEditor);
45
46   application.SendNotification();
47   application.Render();
48
49   Toolkit::Internal::TextEditor& textEditorImpl = GetImpl(textEditor);
50
51   application.SendNotification();
52   application.Render();
53
54   // Highlight the whole text
55   textEditorImpl.SelectWholeText();
56
57   application.SendNotification();
58   application.Render();
59
60   std::string selectedText = textEditorImpl.GetSelectedText();
61   DALI_TEST_CHECK(selectedText == "Hello World");
62
63   // Select None
64   textEditorImpl.SelectNone();
65
66   application.SendNotification();
67   application.Render();
68
69   selectedText = textEditorImpl.GetSelectedText();
70   DALI_TEST_CHECK(selectedText == "");
71
72   END_TEST;
73 }
74
75 int UtcDaliTextEditorMarkupUnderline(void)
76 {
77   ToolkitTestApplication application;
78   tet_infoline(" UtcDaliTextEditorMarkupUnderline ");
79
80   TextEditor textEditor = TextEditor::New();
81
82   application.GetScene().Add(textEditor);
83
84   textEditor.SetProperty(TextEditor::Property::TEXT, "<u>ABC</u>EF<u>GH</u>");
85   textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
86
87   application.SendNotification();
88   application.Render();
89
90   uint32_t expectedNumberOfUnderlinedGlyphs = 5u;
91
92   Toolkit::Internal::TextEditor& textEditorImpl        = GetImpl(textEditor);
93   const Text::Length             numberOfUnderlineRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfUnderlineRuns();
94
95   DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
96
97   Vector<UnderlinedGlyphRun> underlineRuns;
98   underlineRuns.Resize(numberOfUnderlineRuns);
99   textEditorImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
100
101   //ABC are underlined
102   DALI_TEST_EQUALS(underlineRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
103   DALI_TEST_EQUALS(underlineRuns[1u].glyphRun.glyphIndex, 1u, TEST_LOCATION);
104   DALI_TEST_EQUALS(underlineRuns[2u].glyphRun.glyphIndex, 2u, TEST_LOCATION);
105
106   //GH are underlined
107   DALI_TEST_EQUALS(underlineRuns[3u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
108   DALI_TEST_EQUALS(underlineRuns[4u].glyphRun.glyphIndex, 6u, TEST_LOCATION);
109
110   END_TEST;
111 }
112
113 int UtcDaliTextEditorMarkupUnderlineAttributes(void)
114 {
115   ToolkitTestApplication application;
116   tet_infoline(" UtcDaliTextEditorMarkupUnderlineAttributes ");
117
118   TextEditor textEditor = TextEditor::New();
119
120   application.GetScene().Add(textEditor);
121
122   std::string testText =
123     "start<u>ABC1</u>then"
124     "<u type='solid'>ABC2</u>then"
125     "<u type='dashed'>ABC3</u>then"
126     "<u type='double'>ABC4</u>then"
127     "<u color='green'>ABC5</u>then"
128     "<u height='5.0f'>ABC6</u>then"
129     "<u type='dashed' dash-gap='3.0f'>ABC7</u>then"
130     "<u type='dashed' dash-width='4.0f'>ABC8</u>then"
131     "<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>ABC9</u>end"
132
133     ;
134
135   textEditor.SetProperty(TextEditor::Property::TEXT, testText);
136   textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
137
138   application.SendNotification();
139   application.Render();
140
141   const uint32_t NUMBER_OF_CASES                  = 9u;
142   uint32_t       expectedNumberOfUnderlinedGlyphs = 36u;
143
144   Toolkit::Internal::TextEditor& textEditorImpl        = GetImpl(textEditor);
145   const Text::Length             numberOfUnderlineRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfUnderlineRuns();
146
147   DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
148
149   Vector<UnderlinedGlyphRun> underlineRuns;
150   underlineRuns.Resize(numberOfUnderlineRuns);
151   textEditorImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
152
153   struct DataOfCase
154   {
155     std::string              title;
156     uint32_t                 startIndex;
157     uint32_t                 endIndex;
158     GlyphIndex               startGlyphIndex;
159     GlyphIndex               endGlyphIndex;
160     UnderlineStyleProperties properties;
161   };
162   DataOfCase data[] =
163     {
164       //<u>ABC1</u>
165       {"<u>ABC1</u>",
166        0u,
167        3u,
168        5u,
169        8u,
170        {
171          Text::Underline::SOLID,
172          Color::BLACK,
173          0u,
174          1u,
175          2u,
176          false,
177          false,
178          false,
179          false,
180          false,
181        }},
182
183       //<u type='solid'>ABC2</u>
184       {"<u type='solid'>ABC2</u>",
185        4u,
186        7u,
187        13u,
188        16u,
189        {
190          Text::Underline::SOLID,
191          Color::BLACK,
192          0u,
193          1u,
194          2u,
195          true,
196          false,
197          false,
198          false,
199          false,
200        }},
201
202       //<u type='dashed'>ABC3</u>
203       {"<u type='dashed'>ABC3</u>",
204        8u,
205        11u,
206        21u,
207        24u,
208        {
209          Text::Underline::DASHED,
210          Color::BLACK,
211          0u,
212          1u,
213          2u,
214          true,
215          false,
216          false,
217          false,
218          false,
219        }},
220
221       //<u type='double'>ABC4</u>
222       {"<u type='double'>ABC4</u>",
223        12u,
224        15u,
225        29u,
226        32u,
227        {
228          Text::Underline::DOUBLE,
229          Color::BLACK,
230          0u,
231          1u,
232          2u,
233          true,
234          false,
235          false,
236          false,
237          false,
238        }},
239
240       //<u color='green'>ABC5</u>
241       {"<u color='green'>ABC5</u>",
242        16u,
243        19u,
244        37u,
245        40u,
246        {
247          Text::Underline::SOLID,
248          Color::GREEN,
249          0u,
250          1u,
251          2u,
252          false,
253          true,
254          false,
255          false,
256          false,
257        }},
258
259       //<u height='5.0f'>ABC6</u>
260       {"<u height='5.0f'>ABC6</u>",
261        20u,
262        23u,
263        45u,
264        48u,
265        {
266          Text::Underline::SOLID,
267          Color::BLACK,
268          5u,
269          1u,
270          2u,
271          false,
272          false,
273          true,
274          false,
275          false,
276        }},
277
278       //<u type='dashed' dash-gap='3.0f'>ABC7</u>
279       {"<u type='dashed' dash-gap='3.0f'>ABC7</u>",
280        24u,
281        27u,
282        53u,
283        56u,
284        {
285          Text::Underline::DASHED,
286          Color::BLACK,
287          0u,
288          3u,
289          2u,
290          true,
291          false,
292          false,
293          true,
294          false,
295        }},
296
297       //<u type='dashed' dash-width='4.0f'>ABC8</u>
298       {"<u type='dashed' dash-width='4.0f'>ABC8</u>",
299        28u,
300        31u,
301        61u,
302        64u,
303        {
304          Text::Underline::DASHED,
305          Color::BLACK,
306          0u,
307          1u,
308          4u,
309          true,
310          false,
311          false,
312          false,
313          true,
314        }},
315
316       //<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>
317       {"<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>",
318        32u,
319        35u,
320        69u,
321        72u,
322        {
323          Text::Underline::DASHED,
324          Color::BLUE,
325          4u,
326          2u,
327          3u,
328          true,
329          true,
330          true,
331          true,
332          true,
333        }},
334
335     };
336
337   for(uint32_t i = 0; i < NUMBER_OF_CASES; i++)
338   {
339     tet_infoline(data[i].title.c_str());
340     DALI_TEST_EQUALS(underlineRuns[data[i].startIndex].glyphRun.glyphIndex, data[i].startGlyphIndex, TEST_LOCATION);
341     DALI_TEST_EQUALS(underlineRuns[data[i].endIndex].glyphRun.glyphIndex, data[i].endGlyphIndex, TEST_LOCATION);
342
343     DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].startIndex].properties);
344     DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].endIndex].properties);
345   }
346
347   END_TEST;
348 }
349
350 int UtcDaliTextEditorFontPointSizeLargerThanAtlas(void)
351 {
352   ToolkitTestApplication application;
353   tet_infoline(" UtcDaliTextEditorFontPointSizeLargerThanAtlas ");
354
355   // Create a text editor
356   TextEditor textEditor = TextEditor::New();
357   //Set size to avoid automatic eliding
358   textEditor.SetProperty(Actor::Property::SIZE, Vector2(1025, 1025));
359   //Set very large font-size using point-size
360   textEditor.SetProperty(TextEditor::Property::POINT_SIZE, 1000);
361   //Specify font-family
362   textEditor.SetProperty(TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
363   //Set text to check if appear or not
364   textEditor.SetProperty(TextEditor::Property::TEXT, "A");
365
366   application.GetScene().Add(textEditor);
367
368   application.SendNotification();
369   application.Render();
370
371   //Check if Glyph is added to AtlasGlyphManger or not
372   int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
373   DALI_TEST_EQUALS(countAtlas, 1, TEST_LOCATION);
374
375   END_TEST;
376 }
377
378 int UtcDaliTextEditorFontPointSizeLargerThanAtlasPlaceholderCase(void)
379 {
380   ToolkitTestApplication application;
381   tet_infoline(" UtcDaliTextEditorFontPointSizeLargerThanAtlasPlaceholderCase ");
382
383   //Set Map of placeholder: text, font-family and point-size
384   Property::Map placeholderMapSet;
385   placeholderMapSet["text"]       = "A";
386   placeholderMapSet["fontFamily"] = "DejaVu Sans";
387   placeholderMapSet["pixelSize"]  = 1000.0f;
388
389   // Create a text editor
390   TextEditor textEditor = TextEditor::New();
391   //Set size to avoid automatic eliding
392   textEditor.SetProperty(Actor::Property::SIZE, Vector2(1025, 1025));
393   //Set placeholder
394   textEditor.SetProperty(TextEditor::Property::PLACEHOLDER, placeholderMapSet);
395
396   application.GetScene().Add(textEditor);
397
398   application.SendNotification();
399   application.Render();
400
401   //Check if Glyph is added to AtlasGlyphManger or not
402   int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
403   DALI_TEST_EQUALS(countAtlas, 1, TEST_LOCATION);
404
405   END_TEST;
406 }
407
408 int UtcDaliTextEditorBackgroundTag(void)
409 {
410   ToolkitTestApplication application;
411   tet_infoline("UtcDaliTextEditorBackgroundTag\n");
412
413   TextEditor editor = TextEditor::New();
414   DALI_TEST_CHECK(editor);
415
416   editor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
417   editor.SetProperty(TextEditor::Property::TEXT, "H<background color='red'>e</background> Worl<background color='yellow'>d</background>");
418   application.GetScene().Add(editor);
419   application.SendNotification();
420   application.Render();
421
422   Toolkit::Internal::TextEditor& editorImpl                   = GetImpl(editor);
423   const ColorIndex* const        backgroundColorIndicesBuffer = editorImpl.GetTextController()->GetTextModel()->GetBackgroundColorIndices();
424
425   DALI_TEST_CHECK(backgroundColorIndicesBuffer);
426
427   //default color
428   DALI_TEST_EQUALS(backgroundColorIndicesBuffer[0], 0u, TEST_LOCATION);
429
430   //red color
431   DALI_TEST_EQUALS(backgroundColorIndicesBuffer[1], 1u, TEST_LOCATION);
432
433   //yellow color
434   DALI_TEST_EQUALS(backgroundColorIndicesBuffer[7], 2u, TEST_LOCATION);
435
436   END_TEST;
437 }
438
439 int UtcDaliTextEditorTextWithSpan(void)
440 {
441   ToolkitTestApplication application;
442   tet_infoline("UtcDaliTextEditorTextWithSpan\n");
443
444   TextEditor editor = TextEditor::New();
445   DALI_TEST_CHECK(editor);
446
447   editor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
448   editor.SetProperty(TextEditor::Property::TEXT, "Hello Span");
449   application.GetScene().Add(editor);
450
451   application.SendNotification();
452   application.Render();
453
454   Vector3 originalSize = editor.GetNaturalSize();
455   editor.SetProperty(TextEditor::Property::TEXT, "H<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red'>ello</span> Span");
456
457   application.SendNotification();
458   application.Render();
459
460   Vector3 spanSize = editor.GetNaturalSize();
461
462   DALI_TEST_GREATER(spanSize.width, originalSize.width, TEST_LOCATION);
463
464   Toolkit::Internal::TextEditor& editorImpl          = GetImpl(editor);
465   const ColorIndex* const        colorIndicesBuffer1 = editorImpl.GetTextController()->GetTextModel()->GetColorIndices();
466
467   DALI_TEST_CHECK(colorIndicesBuffer1);
468
469   //default color
470   DALI_TEST_EQUALS(colorIndicesBuffer1[0], 0u, TEST_LOCATION);
471
472   //span color
473   DALI_TEST_EQUALS(colorIndicesBuffer1[1], 1u, TEST_LOCATION);
474
475   //default color
476   DALI_TEST_EQUALS(colorIndicesBuffer1[6], 0u, TEST_LOCATION);
477
478   editor.SetProperty(TextEditor::Property::TEXT, "<span font-size='45'>H</span>ello <span text-color='red'>S</span>pan");
479
480   application.SendNotification();
481   application.Render();
482
483   const ColorIndex* const colorIndicesBuffer2 = editorImpl.GetTextController()->GetTextModel()->GetColorIndices();
484
485   DALI_TEST_CHECK(colorIndicesBuffer2);
486
487   //default color
488   DALI_TEST_EQUALS(colorIndicesBuffer2[0], 0u, TEST_LOCATION);
489
490   //default color
491   DALI_TEST_EQUALS(colorIndicesBuffer2[1], 0u, TEST_LOCATION);
492
493   //span color
494   DALI_TEST_EQUALS(colorIndicesBuffer2[6], 1u, TEST_LOCATION);
495
496   //default color
497   DALI_TEST_EQUALS(colorIndicesBuffer2[7], 0u, TEST_LOCATION);
498
499   END_TEST;
500 }
501
502 int UtcDaliTextEditorControlBackgroundColor(void)
503 {
504   ToolkitTestApplication application;
505   tet_infoline(" UtcDaliTextEditorControlBackgroundColor\n");
506
507   TextEditor editor = TextEditor::New();
508   DALI_TEST_CHECK(editor);
509
510   Vector4 backgroundColor;
511
512   editor.SetProperty(TextEditor::Property::TEXT, "Background Color");
513   application.GetScene().Add(editor);
514   application.SendNotification();
515   application.Render();
516
517   Toolkit::Internal::TextEditor& editorImpl     = GetImpl(editor);
518   ControllerPtr                  controller     = editorImpl.GetTextController();
519   Controller::Impl&              controllerImpl = Controller::Impl::GetImplementation(*controller.Get());
520
521   // Default color is transparent
522   controllerImpl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
523   DALI_TEST_EQUALS(backgroundColor, Color::TRANSPARENT, TEST_LOCATION);
524
525   // Set background color to red
526   editor.SetBackgroundColor(Color::RED);
527   application.SendNotification();
528   application.Render();
529
530   // Should be red
531   controllerImpl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
532   DALI_TEST_EQUALS(backgroundColor, Color::RED, TEST_LOCATION);
533
534   END_TEST;
535 }
536
537 int UtcDaliTextEditorTextPositionWithMinLineAndBigFont(void)
538 {
539   ToolkitTestApplication application;
540   tet_infoline(" UtcDaliTextEditorTextPositionWithMinLine ");
541
542   TextEditor textEditor = TextEditor::New();
543
544   textEditor.SetProperty(TextEditor::Property::TEXT, "<span font-size='45'>H</span>\ni");
545   textEditor.SetProperty(DevelTextEditor::Property::MIN_LINE_SIZE, 50);
546   textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
547
548   application.GetScene().Add(textEditor);
549
550   application.SendNotification();
551   application.Render();
552
553   Toolkit::Internal::TextEditor& textEditorImpl = GetImpl(textEditor);
554   Text::ViewInterface&           view           = textEditorImpl.GetTextController()->GetView();
555
556   Length numberOfGlyphs = view.GetNumberOfGlyphs();
557
558   DALI_TEST_EQUALS(numberOfGlyphs, 3u, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
559
560   Vector<GlyphInfo> glyphs;
561   glyphs.Resize(numberOfGlyphs);
562
563   Vector<Vector2> positions;
564   positions.Resize(numberOfGlyphs);
565
566   float alignmentOffset = 0u;
567   numberOfGlyphs        = view.GetGlyphs(glyphs.Begin(),
568                                   positions.Begin(),
569                                   alignmentOffset,
570                                   0u,
571                                   numberOfGlyphs);
572
573   DALI_TEST_EQUALS(positions[2].y, 165.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
574
575   END_TEST;
576 }
577
578 int UtcDaliTextEditorMarkupStrikethrough(void)
579 {
580   ToolkitTestApplication application;
581   tet_infoline(" UtcDaliTextEditorMarkupStrikethrough ");
582
583   TextEditor textEditor = TextEditor::New();
584
585   application.GetScene().Add(textEditor);
586
587   textEditor.SetProperty(TextEditor::Property::TEXT, "<s>ABC</s>EF<s color='red'>GH</s>");
588   textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
589
590   application.SendNotification();
591   application.Render();
592
593   uint32_t expectedNumberOfStrikethroughGlyphs = 2u;
594
595   Toolkit::Internal::TextEditor& textEditorImpl            = GetImpl(textEditor);
596   const Text::Length             numberOfStrikethroughRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
597
598   DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION);
599
600   Vector<StrikethroughGlyphRun> strikethroughRuns;
601   strikethroughRuns.Resize(numberOfStrikethroughRuns);
602   textEditorImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
603
604   //ABC have strikethrough
605   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
606   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION);
607   DALI_TEST_CHECK(!strikethroughRuns[0u].isColorSet);
608
609   //GH have strikethrough
610   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
611   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.numberOfGlyphs, 2u, TEST_LOCATION);
612   DALI_TEST_CHECK(strikethroughRuns[1u].isColorSet);
613
614   END_TEST;
615 }
616
617 int UtcDaliTextEditorMarkupStrikethroughNoEndTag(void)
618 {
619   ToolkitTestApplication application;
620   tet_infoline(" UtcDaliTextEditorMarkupStrikethroughNoEndTag ");
621
622   TextEditor textEditor = TextEditor::New();
623
624   application.GetScene().Add(textEditor);
625
626   textEditor.SetProperty(TextEditor::Property::TEXT, "<s>ABC");
627   textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
628
629   application.SendNotification();
630   application.Render();
631
632   uint32_t expectedNumberOfStrikethroughGlyphs = 0u;
633
634   Toolkit::Internal::TextEditor& textEditorImpl            = GetImpl(textEditor);
635   Text::Length                   numberOfStrikethroughRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
636
637   DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION);
638
639   END_TEST;
640 }