2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <dali/devel-api/text-abstraction/bidirectional-support.h>
22 #include <dali-toolkit/internal/text/bidirectional-support.h>
23 #include <dali-toolkit/internal/text/character-set-conversion.h>
24 #include <dali-toolkit/internal/text/text-run-container.h>
25 #include <dali-toolkit-test-suite-utils.h>
26 #include <dali-toolkit/dali-toolkit.h>
27 #include <toolkit-text-utils.h>
30 using namespace Toolkit;
33 // Tests the following functions.
35 // void SetBidirectionalInfo( const Vector<Character>& text,
36 // const Vector<ScriptRun>& scripts,
37 // const Vector<LineBreakInfo>& lineBreakInfo,
38 // CharacterIndex startIndex,
39 // Length numberOfCharacters,
40 // Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
41 // bool GetMirroredText( const Vector<Character>& text,
42 // Vector<CharacterDirection>& directions,
43 // const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
44 // CharacterIndex startIndex,
45 // Length numberOfCharacters,
46 // Vector<Character>& mirroredText )
47 // void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
48 // Length totalNumberOfCharacters,
49 // CharacterIndex startIndex,
50 // Length numberOfCharacters,
51 // Vector<CharacterDirection>& directions )
53 //////////////////////////////////////////////////////////
58 struct SetBidirectionalInfoData
60 std::string description; ///< Description of the test.
61 std::string text; ///< Input text.
62 unsigned int startIndex; ///< The index from where the model is updated.
63 unsigned int numberOfCharacters; ///< The number of characters to update.
64 unsigned int numberOfParagraphs; ///< The expected number of bidirectional paragraphs.
65 unsigned int* indices; ///< The expected indices to the first character of each paragraph.
66 unsigned int* numberOfParagraphCharacters; ///< The expected number of characters of each paragraph.
67 bool* directions; ///< The expected direction of each paragraph.
72 unsigned int characterIndex;
73 unsigned int numberOfCharacters;
74 unsigned int* visualToLogical;
77 struct GetMirroredTextData
79 std::string description; ///< Description of the test.
80 std::string text; ///< Input text.
81 unsigned int startIndex; ///< The index from where the model is updated.
82 unsigned int numberOfCharacters; ///< The number of the characters.
83 std::string mirroredText; ///< The expected result.
86 struct GetCharactersDirectionData
88 std::string description; ///< Description of the test.
89 std::string text; ///< Input text.
90 unsigned int startIndex; ///< The index from where the model is updated.
91 unsigned int numberOfCharacters; ///< The number of characters.
92 bool* directions; ///< The expected directions.
93 bool markupProcessorEnabled; ///< Enable markup processor to use markup text.
96 bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
98 // 1) Create the model.
101 Size textArea(100.f, 60.f);
105 const Vector<FontDescriptionRun> fontDescriptions;
106 const LayoutOptions options;
107 CreateTextModel( data.text,
117 Toolkit::DevelText::EllipsisPosition::END );
119 LogicalModelPtr logicalModel = textModel->mLogicalModel;
120 VisualModelPtr visualModel = textModel->mVisualModel;
122 // 2) Clear the bidirectional paragraph info data.
123 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
124 if( 0u != data.numberOfCharacters )
126 ClearCharacterRuns( data.startIndex,
127 data.startIndex + data.numberOfCharacters - 1u,
131 // 3) Call the SetBidirectionalInfo() function.
132 SetBidirectionalInfo( logicalModel->mText,
133 logicalModel->mScriptRuns,
134 logicalModel->mLineBreakInfo,
136 data.numberOfCharacters,
139 // 4) Compare with the expected results.
140 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
142 if( data.numberOfParagraphs != bidirectionalInfo.Count() )
144 // Different number of expected bidirectional paragraphs.
145 std::cout << " Different number of bidi paragraphs : " << bidirectionalInfo.Count() << ", expected : " << data.numberOfParagraphs << std::endl;
149 for( unsigned int index = 0u; index < data.numberOfParagraphs; ++index )
151 const BidirectionalParagraphInfoRun& run = bidirectionalInfo[index];
153 const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( run.bidirectionalInfoIndex );
154 if( direction != data.directions[index] )
156 std::cout << " Different direction" << std::endl;
157 std::cout << " paragraph : " << index << std::endl;
158 std::cout << " index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
159 std::cout << " expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
163 if( run.characterRun.characterIndex != data.indices[index] )
165 std::cout << " Different index" << std::endl;
166 std::cout << " paragraph : " << index << std::endl;
167 std::cout << " index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
168 std::cout << " expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
171 if( run.characterRun.numberOfCharacters != data.numberOfParagraphCharacters[index] )
173 std::cout << " Different number of characters" << std::endl;
174 std::cout << " paragraph : " << index << std::endl;
175 std::cout << " index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
176 std::cout << " expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
184 bool GetMirroredTextTest( const GetMirroredTextData& data )
186 // 1) Create the model.
189 Size textArea(100.f, 60.f);
193 const Vector<FontDescriptionRun> fontDescriptions;
194 const LayoutOptions options;
195 CreateTextModel( data.text,
205 Toolkit::DevelText::EllipsisPosition::END );
207 LogicalModelPtr logicalModel = textModel->mLogicalModel;
208 VisualModelPtr visualModel = textModel->mVisualModel;
210 // 2) Call the GetMirroredText() function for the whole text
211 Vector<Character> mirroredText;
212 bool mirrored = false;
213 mirrored = GetMirroredText( logicalModel->mText,
214 logicalModel->mCharacterDirections,
215 logicalModel->mBidirectionalParagraphInfo,
217 logicalModel->mText.Count(),
220 // 3) Call the GetMirroredText() function for the given index + number of characters
221 mirrored = GetMirroredText( logicalModel->mText,
222 logicalModel->mCharacterDirections,
223 logicalModel->mBidirectionalParagraphInfo,
225 data.numberOfCharacters,
228 // 4) Compare the results.
231 std::string mirroredString;
232 Utf32ToUtf8( mirroredText.Begin(),
233 mirroredText.Count(),
236 if( !mirrored && ( mirroredString != data.text ) )
238 std::cout << " No mirrored text and mirroredString != data.text." << std::endl;
239 std::cout << " mirrored string : [" << mirroredString << "]" << std::endl;
240 std::cout << " text : [" << data.text << "]" << std::endl;
244 if( mirrored && ( mirroredString == data.text ) )
246 std::cout << " Mirrored text and mirroredString == data.text." << std::endl;
247 std::cout << " mirrored string : [" << mirroredString << "]" << std::endl;
248 std::cout << " text : [" << data.text << "]" << std::endl;
252 if( mirrored && ( mirroredString != data.mirroredText ) )
254 std::cout << " Mirrored text and mirroredString != data.mirroredText." << std::endl;
255 std::cout << " mirrored string : [" << mirroredString << "]" << std::endl;
256 std::cout << " text : [" << data.mirroredText << "]" << std::endl;
263 bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
265 // 1) Create the model.
268 Size textArea(100.f, 60.f);
272 const Vector<FontDescriptionRun> fontDescriptions;
273 const LayoutOptions options;
274 CreateTextModel( data.text,
281 data.markupProcessorEnabled,
284 Toolkit::DevelText::EllipsisPosition::END );
286 LogicalModelPtr logicalModel = textModel->mLogicalModel;
287 VisualModelPtr visualModel = textModel->mVisualModel;
289 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
291 // 2) Clear the direction info data.
292 Vector<CharacterDirection>& directions = logicalModel->mCharacterDirections;
294 if( directions.Count() >= data.startIndex + data.numberOfCharacters )
296 directions.Erase( directions.Begin() + data.startIndex,
297 directions.Begin() + data.startIndex + data.numberOfCharacters );
300 // 3) Call GetCharactersDirection() function.
302 GetCharactersDirection( bidirectionalInfo,
303 logicalModel->mText.Count(),
305 data.numberOfCharacters,
308 for( unsigned int index = 0u; index < logicalModel->mText.Count(); ++index )
310 if( data.directions[index] != directions[index] )
321 //////////////////////////////////////////////////////////
323 int UtcDaliSetBidirectionalInfo(void)
325 tet_infoline(" UtcDaliSetBidirectionalInfo");
327 unsigned int indices01[] = {};
328 unsigned int numberOfCharacters01[] = {};
329 bool direction01[] = {};
330 unsigned int indices02[] = {};
331 unsigned int numberOfCharacters02[] = {};
332 bool direction02[] = {};
333 unsigned int indices03[] = { 17u, 48u };
334 unsigned int numberOfCharacters03[] = { 14u, 14u };
335 bool direction03[] = { true, true };
336 unsigned int indices04[] = { 17u, 31u, 79u };
337 unsigned int numberOfCharacters04[] = { 14u, 48u, 31u };
338 bool direction04[] = { true, false, true };
339 unsigned int indices05[] = { 17u, 41u, 117u };
340 unsigned int numberOfCharacters05[] = { 24u, 76u, 49u };
341 bool direction05[] = { true, false, true };
342 unsigned int indices06[] = { 17u, 48u };
343 unsigned int numberOfCharacters06[] = { 14u, 14u };
344 bool direction06[] = { true, true };
345 unsigned int indices07[] = { 17u, 31u, 79u };
346 unsigned int numberOfCharacters07[] = { 14u, 48u, 31u };
347 bool direction07[] = { true, false, true };
348 unsigned int indices08[] = { 17u, 41u, 117u };
349 unsigned int numberOfCharacters08[] = { 24u, 76u, 49u };
350 bool direction08[] = { true, false, true };
352 struct SetBidirectionalInfoData data[] =
361 numberOfCharacters01,
365 "Some left to right paragraphs",
366 "Hello world\ndemo\n\n",
371 numberOfCharacters02,
375 "A mix of left to right and right to left paragraphs.",
376 "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
381 numberOfCharacters03,
385 "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
386 "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
391 numberOfCharacters04,
395 "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts.",
396 "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
401 numberOfCharacters05,
405 "A mix of left to right and right to left paragraphs. Updates a left to right paragraph.",
406 "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
411 numberOfCharacters06,
415 "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
416 "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
421 numberOfCharacters07,
425 "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates initial paragraphs.",
426 "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
431 numberOfCharacters08,
435 "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates mid paragraphs.",
436 "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
441 numberOfCharacters08,
445 "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates from character 85",
446 "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
451 numberOfCharacters08,
455 const unsigned int numberOfTests = 10u;
457 for( unsigned int index = 0u; index < numberOfTests; ++index )
459 ToolkitTestApplication application;
460 if( !SetBidirectionalInfoTest( data[index] ) )
462 tet_result(TET_FAIL);
466 tet_result(TET_PASS);
470 int UtcDaliGetMirroredText(void)
472 tet_infoline(" UtcDaliGetMirroredText");
474 struct GetMirroredTextData data[] =
484 "Left to right characters only.",
485 "Hello world\nhello world demo.",
488 "Hello world\nhello world demo."
491 "Right to left characters but with no characters to mirror.",
492 "שלום עולם\nمرحبا بالعالم",
495 "שלום עולם\nمرحبا بالعالم"
498 "Right to left characters with some characters to mirror.",
499 "שלום עולם\n(مرحبا بالعالم)",
502 "שלום עולם\n)مرحبا بالعالم("
505 "Right to left characters with some characters to mirror. Update last paragraph.",
506 "שלום עולם\n(مرحبا بالعالم)",
509 "שלום עולם\n)مرحبا بالعالم("
512 "Mix of bidirectional text. With more paragraphs.",
513 "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
514 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
517 "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
518 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום )hello) world demo )עולם(\nשלום )مرحبا بالعالم עולם( )hello("
521 "Mix of bidirectional text. With more paragraphs. Update middle paragraphs.",
522 "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
523 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
526 "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
527 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
530 "Mix of bidirectional text. With more paragraphs. Update middle paragraphs (2).",
531 "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
532 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
535 "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
536 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
539 const unsigned int numberOfTests = 8u;
541 for( unsigned int index = 0u; index < numberOfTests; ++index )
543 ToolkitTestApplication application;
544 if( !GetMirroredTextTest( data[index] ) )
546 tet_result(TET_FAIL);
550 tet_result(TET_PASS);
554 int UtcDaliGetCharactersDirection(void)
556 tet_infoline(" UtcDaliGetCharactersDirection");
558 bool directions01[] = {};
559 bool directions02[] = {
560 false, false, false, false, false, false, false, false, false, false,
561 false, false, false, false, false, false, false, false, false, false,
562 false, false, false, false, false, false, false, false };
563 bool directions03[] = {
564 true, true, true, true, true, true, true, true, true, true,
565 true, true, true, true, true, true, true, true, true };
566 bool directions04[] = {
567 false, false, false, false, false, false, false, false, false, false,
568 false, false, false, false, false, false, false, false, false, false,
569 false, false, false, false, true, true, true, true, true, true,
570 true, true, true, false, true, true, true, true, true, true,
571 true, true, true, true, false, false, false, false, false, false,
572 false, false, false, false, false };
573 bool directions05[] = {
574 false, false, false, false, false, false, false, false, false, false,
575 false, false, false, false, false, false, false, false, false, false,
576 false, false, false, false, false, false, false, false, false, false,
577 false, false, false, false, false, false, false, false, false, false,
578 false, true, true, true, true, true, true, true, true, true,
579 true, true, true, true, true, true, true, true, true, true,
580 true, true, true, true, false, true, true, true, true, true,
581 true, true, true, true, true, true, true, true, true, true,
582 true, true, true, true, true, true, true, true, true, false,
583 false, false, false, false, true, true, true, true, true, true,
584 true, true, true, true, true, true, true, true, true, false,
585 false, false, false, false, true, true, true, true, true, true,
586 true, true, true, true, true, true, true, true, true, true,
587 true, true, true, true, true, true, true, true, true, false,
588 false, false, false, false, false, false, false, false, false, false,
589 false, false, false, false, false, false, false, false, false, false,
590 false, false, true, true, true, true, true, true, true, true,
591 true, true, true, true, true, true, false, false, false, false,
592 false, false, false, false, false, false, false, false, false, false,
593 false, false, true, true, true, true, true, true, true, true,
594 true, true, true, true, true, true, true, true, true, true,
595 true, true, true, true, true, true, true, true, true, true,
596 true, true, false, false, false, false, false };
598 bool directions06[] = {
599 true, true, true, true, true, true, true, true, true, true,
600 false, false, false, false, false, false, false, false, false, false,
601 false, false, false, false, false, false };
603 struct GetCharactersDirectionData data[] =
614 "Left to right characters only",
615 "Hello world\nhello world demo",
622 "Right to left characters only",
623 "שלום עולם\nשלום עולם",
630 "Mix of bidirectional text",
631 "Hello world\nhello world שלום עולם\nשלום עולם hello world",
638 "Mix of bidirectional text. With more paragraphs.",
639 "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
640 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
647 "Mix of bidirectional text. With more paragraphs. Update first paragraph.",
648 "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
649 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
656 "Mix of bidirectional text. With more paragraphs. Update from character 29",
657 "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
658 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
665 "Mix of bidirectional text. With more paragraphs. Update from character 163",
666 "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
667 " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
674 "Mix of bidirectional text. With brackets and LRM",
675 "שלום עולם ‎(hello)[world]‎",
682 const unsigned int numberOfTests = 9u;
684 for( unsigned int index = 0u; index < numberOfTests; ++index )
686 ToolkitTestApplication application;
687 if( !GetCharactersDirectionTest( data[index] ) )
689 tet_result(TET_FAIL);
693 tet_result(TET_PASS);