2 * Copyright (c) 2022 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.
22 #include <dali-toolkit-test-suite-utils.h>
23 #include <dali-toolkit/dali-toolkit.h>
24 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
25 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
26 #include <dali-toolkit/internal/text/text-run-container.h>
27 #include <toolkit-text-utils.h>
30 using namespace Toolkit;
33 // Tests the LayoutEngine methods.
35 //////////////////////////////////////////////////////////
39 const std::string DEFAULT_FONT_DIR("/resources/fonts");
43 std::string description;
46 unsigned int numberOfFonts;
47 FontDescriptionRun* fontDescriptions;
49 unsigned int totalNumberOfGlyphs;
51 unsigned int numberOfLines;
53 Layout::Engine::Type layout;
54 unsigned int startIndex;
55 unsigned int numberOfGlyphs;
58 float characterSpacing;
61 void Print(const LineRun& line)
63 std::cout << " glyph run, index : " << line.glyphRun.glyphIndex << ", num glyphs : " << line.glyphRun.numberOfGlyphs << std::endl;
64 std::cout << " character run, index : " << line.characterRun.characterIndex << ", num chars : " << line.characterRun.numberOfCharacters << std::endl;
65 std::cout << " width : " << floor(line.width) << std::endl;
66 std::cout << " ascender : " << line.ascender << std::endl;
67 std::cout << " descender : " << line.descender << std::endl;
68 std::cout << " extraLength : " << line.extraLength << std::endl;
69 std::cout << " alignmentOffset : " << line.alignmentOffset << std::endl;
70 std::cout << " direction : " << line.direction << std::endl;
71 std::cout << " ellipsis : " << line.ellipsis << std::endl;
74 bool LayoutTextTest(const LayoutTextData& data)
77 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
78 fontClient.SetDpi(96u, 96u);
80 char* pathNamePtr = get_current_dir_name();
81 const std::string pathName(pathNamePtr);
84 fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf");
85 fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf");
86 fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansArabicRegular.ttf");
87 fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHindiRegular.ttf");
89 // 1) Create the model.
94 Vector<FontDescriptionRun> fontDescriptionRuns;
95 if(0u != data.numberOfFonts)
97 fontDescriptionRuns.Insert(fontDescriptionRuns.End(),
98 data.fontDescriptions,
99 data.fontDescriptions + data.numberOfFonts);
102 LayoutOptions options;
103 options.align = false;
104 CreateTextModel(data.text,
114 Toolkit::DevelText::EllipsisPosition::END,
116 data.characterSpacing);
118 LogicalModelPtr logicalModel = textModel->mLogicalModel;
119 VisualModelPtr visualModel = textModel->mVisualModel;
121 // 2) Clear the layout.
122 Vector<LineRun>& lines = visualModel->mLines;
124 const Length numberOfCharacters = logicalModel->mText.Count();
125 const bool isLastNewParagraph = (0u == numberOfCharacters) ? false : TextAbstraction::IsNewParagraph(*(logicalModel->mText.Begin() + (numberOfCharacters - 1u)));
126 const GlyphIndex lastGlyphIndex = data.startIndex + data.numberOfGlyphs - 1u;
127 const bool removeLastLine = isLastNewParagraph && (lastGlyphIndex + 1u == visualModel->mGlyphs.Count());
129 LineIndex startRemoveIndex = 0u;
131 if(0u != lines.Count())
133 startRemoveIndex = lines.Count();
134 LineIndex endRemoveIndex = startRemoveIndex;
135 ClearGlyphRuns(data.startIndex,
136 lastGlyphIndex + (removeLastLine ? 1u : 0u),
141 // Update the character runs of the lines.
142 const CharacterIndex* const glyphsToCharactersBuffer = visualModel->mGlyphsToCharacters.Begin();
143 const Length* const charactersPerGlyph = visualModel->mCharactersPerGlyph.Begin();
144 const CharacterIndex startCharacterIndex = *(glyphsToCharactersBuffer + data.startIndex);
145 const CharacterIndex lastCharacterIndex = *(glyphsToCharactersBuffer + lastGlyphIndex) + *(charactersPerGlyph + lastGlyphIndex) - 1u;
146 ClearCharacterRuns(startCharacterIndex,
147 lastCharacterIndex + (removeLastLine ? 1u : 0u),
152 lines.Erase(lines.Begin() + startRemoveIndex,
153 lines.Begin() + endRemoveIndex);
156 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
158 glyphPositions.Erase(glyphPositions.Begin() + data.startIndex,
159 glyphPositions.Begin() + data.startIndex + data.numberOfGlyphs);
162 Layout::Engine engine;
163 engine.SetMetrics(metrics);
164 engine.SetLayout(data.layout);
166 textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
167 textModel->mLineWrapMode = LineWrap::WORD;
168 textModel->mIgnoreSpacesAfterText = true;
169 //textModel->mMatchSystemLanguageDirection = false;
170 Layout::Parameters layoutParameters(data.textArea,
173 layoutParameters.isLastNewParagraph = isLastNewParagraph;
175 // The initial glyph and the number of glyphs to layout.
176 layoutParameters.startGlyphIndex = data.startIndex;
177 layoutParameters.numberOfGlyphs = data.numberOfGlyphs;
178 layoutParameters.startLineIndex = startRemoveIndex;
179 layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
181 layoutSize = Vector2::ZERO;
183 bool isAutoScroll = false;
184 bool isAutoScrollMaxTextureExceeded = false;
185 bool isHiddenInputEnabled = false;
186 const bool updated = engine.LayoutText(layoutParameters,
190 isAutoScrollMaxTextureExceeded,
191 isHiddenInputEnabled,
192 DevelText::EllipsisPosition::END);
194 // 4) Compare the results.
196 if(updated != data.updated)
198 std::cout << " Different updated bool : " << updated << ", expected : " << data.updated << std::endl;
202 if(layoutSize != data.layoutSize)
204 std::cout << " Different layout size : " << layoutSize << ", expected : " << data.layoutSize << std::endl;
208 for(unsigned int index = 0u; index < data.totalNumberOfGlyphs; ++index)
210 const Vector2& position = *(glyphPositions.Begin() + index);
212 if(fabsf(std::round(position.x) - std::round(*(data.positions + 2u * index))) > Math::MACHINE_EPSILON_1000)
214 std::cout << " Different position for glyph " << index << " x : " << position.x << ", expected : " << *(data.positions + 2u * index) << std::endl;
217 if(fabsf(position.y - *(data.positions + 2u * index + 1u)) > Math::MACHINE_EPSILON_1000)
219 std::cout << " Different position for glyph " << index << " y : " << position.y << ", expected : " << *(data.positions + 2u * index + 1u) << std::endl;
224 if(lines.Count() != data.numberOfLines)
226 std::cout << " Different number of lines : " << lines.Count() << ", expected : " << data.numberOfLines << std::endl;
230 for(unsigned int index = 0u; index < data.numberOfLines; ++index)
232 const LineRun& line = *(lines.Begin() + index);
233 const LineRun& expectedLine = *(data.lines + index);
235 if(line.glyphRun.glyphIndex != expectedLine.glyphRun.glyphIndex)
237 std::cout << " Different line info for line : " << index << std::endl;
239 std::cout << " expected" << std::endl;
243 if(line.glyphRun.numberOfGlyphs != expectedLine.glyphRun.numberOfGlyphs)
245 std::cout << " Different line info for line : " << index << std::endl;
247 std::cout << " expected" << std::endl;
252 if(line.characterRun.characterIndex != expectedLine.characterRun.characterIndex)
254 std::cout << " Different line info for line : " << index << std::endl;
256 std::cout << " expected" << std::endl;
260 if(line.characterRun.numberOfCharacters != expectedLine.characterRun.numberOfCharacters)
262 std::cout << " Different line info for line : " << index << std::endl;
264 std::cout << " expected" << std::endl;
269 if(fabsf(floor(line.width) - expectedLine.width) > Math::MACHINE_EPSILON_1)
271 std::cout << " Different line info for line : " << index << std::endl;
273 std::cout << " expected" << std::endl;
278 if(fabsf(line.ascender - expectedLine.ascender) > Math::MACHINE_EPSILON_1)
280 std::cout << " Different line info for line : " << index << std::endl;
282 std::cout << " expected" << std::endl;
287 if(fabsf(line.descender - expectedLine.descender) > Math::MACHINE_EPSILON_1)
289 std::cout << " Different line info for line : " << index << std::endl;
291 std::cout << " expected" << std::endl;
296 if(fabsf(line.extraLength - expectedLine.extraLength) > Math::MACHINE_EPSILON_1)
298 std::cout << " Different line info for line : " << index << std::endl;
300 std::cout << " expected" << std::endl;
305 if(line.ellipsis != expectedLine.ellipsis)
307 std::cout << " Different line info for line : " << index << std::endl;
309 std::cout << " expected" << std::endl;
313 // Do not compare the alignment offset as it's not calculated in the layout.
314 // Do not compare the line direction as it's not set in the layout.
320 ////////////////////////////////////////////////////////
324 //////////////////////////////////////////////////////////
326 // UtcDaliTextCharacterSpacingSingleLineTextArea1
327 // UtcDaliTextCharacterSpacingSingleLineTextArea2
328 // UtcDaliTextCharacterSpacingSingleLineTextArea3
329 // UtcDaliTextCharacterSpacingMultilineText1
330 // UtcDaliTextCharacterSpacingMultilineText2
332 //////////////////////////////////////////////////////////
334 int UtcDaliTextCharacterSpacingSingleLineTextArea1(void)
336 ToolkitTestApplication application;
337 tet_infoline(" UtcDaliTextCharacterSpacingSingleLineTextArea1");
339 // Will layout the text in single line as it can be scrolled.
341 const std::string fontFamily("TizenSans");
343 // Set a known font description
344 FontDescriptionRun fontDescriptionRun;
345 fontDescriptionRun.characterRun.characterIndex = 0u;
346 fontDescriptionRun.characterRun.numberOfCharacters = 11u;
347 fontDescriptionRun.familyLength = fontFamily.size();
348 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
349 memcpy(fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength);
350 fontDescriptionRun.familyDefined = true;
351 fontDescriptionRun.weightDefined = false;
352 fontDescriptionRun.widthDefined = false;
353 fontDescriptionRun.slantDefined = false;
354 fontDescriptionRun.sizeDefined = false;
356 Vector<FontDescriptionRun> fontDescriptionRuns;
357 fontDescriptionRuns.PushBack(fontDescriptionRun);
358 Size textArea(1.f, 1.f);
360 //******* characterSpacing = 0.0f *******//
363 0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f
365 Size layoutSize(79.f, 20.f);
366 //************************************//
368 struct LineRun line =
380 Vector<LineRun> lines;
381 lines.PushBack(line);
383 LayoutTextData data =
385 "Layout text in a small area",
389 fontDescriptionRuns.Begin(),
395 Layout::Engine::SINGLE_LINE_BOX,
402 if(!LayoutTextTest(data))
404 tet_result(TET_FAIL);
407 tet_result(TET_PASS);
411 int UtcDaliTextCharacterSpacingSingleLineTextArea2(void)
413 ToolkitTestApplication application;
414 tet_infoline(" UtcDaliTextCharacterSpacingSingleLineTextArea2");
416 // Will layout the text in single line as it can be scrolled.
418 const std::string fontFamily("TizenSans");
420 // Set a known font description
421 FontDescriptionRun fontDescriptionRun;
422 fontDescriptionRun.characterRun.characterIndex = 0u;
423 fontDescriptionRun.characterRun.numberOfCharacters = 11u;
424 fontDescriptionRun.familyLength = fontFamily.size();
425 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
426 memcpy(fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength);
427 fontDescriptionRun.familyDefined = true;
428 fontDescriptionRun.weightDefined = false;
429 fontDescriptionRun.widthDefined = false;
430 fontDescriptionRun.slantDefined = false;
431 fontDescriptionRun.sizeDefined = false;
433 Vector<FontDescriptionRun> fontDescriptionRuns;
434 fontDescriptionRuns.PushBack(fontDescriptionRun);
435 Size textArea(1.f, 1.f);
437 //******* characterSpacing = 2.0f *******//
440 0.f, -12.f, 12.f, -9.f, 23.f, -13.f, 29.f, -13.f, 34.f, -9.f, 45.f, -0.f, 51.f, -9.f, 65.f, -9.f, 77.f, -9.f, 85.f, -13.f, 90.f, -13.f
442 Size layoutSize(99.f, 20.f);
443 //************************************//
445 struct LineRun line =
457 Vector<LineRun> lines;
458 lines.PushBack(line);
460 LayoutTextData data =
462 "Layout text in a small area",
466 fontDescriptionRuns.Begin(),
472 Layout::Engine::SINGLE_LINE_BOX,
479 if(!LayoutTextTest(data))
481 tet_result(TET_FAIL);
484 tet_result(TET_PASS);
488 int UtcDaliTextCharacterSpacingSingleLineTextArea3(void)
490 ToolkitTestApplication application;
491 tet_infoline(" UtcDaliTextCharacterSpacingSingleLineTextArea3");
493 // Will layout the text in single line as it can be scrolled.
495 const std::string fontFamily("TizenSans");
497 // Set a known font description
498 FontDescriptionRun fontDescriptionRun;
499 fontDescriptionRun.characterRun.characterIndex = 0u;
500 fontDescriptionRun.characterRun.numberOfCharacters = 11u;
501 fontDescriptionRun.familyLength = fontFamily.size();
502 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
503 memcpy(fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength);
504 fontDescriptionRun.familyDefined = true;
505 fontDescriptionRun.weightDefined = false;
506 fontDescriptionRun.widthDefined = false;
507 fontDescriptionRun.slantDefined = false;
508 fontDescriptionRun.sizeDefined = false;
510 Vector<FontDescriptionRun> fontDescriptionRuns;
511 fontDescriptionRuns.PushBack(fontDescriptionRun);
512 Size textArea(1.f, 1.f);
514 //******* characterSpacing = 4.0f *******//
517 0.f, -12.f, 14.f, -9.f, 27.f, -13.f, 35.f, -13.f, 42.f, -9.f, 55.f, -0.f, 63.f, -9.f, 79.f, -9.f, 93.f, -9.f, 103.f, -13.f, 110.f, -13.f
519 Size layoutSize(119.f, 20.f);
520 //************************************//
522 struct LineRun line =
534 Vector<LineRun> lines;
535 lines.PushBack(line);
537 LayoutTextData data =
539 "Layout text in a small area",
543 fontDescriptionRuns.Begin(),
549 Layout::Engine::SINGLE_LINE_BOX,
556 if(!LayoutTextTest(data))
558 tet_result(TET_FAIL);
561 tet_result(TET_PASS);
565 int UtcDaliTextCharacterSpacingMultilineText1(void)
567 ToolkitTestApplication application;
568 tet_infoline(" UtcDaliTextCharacterSpacingMultilineText1");
570 // Layout some lines of left to right text.
572 const std::string fontFamily("TizenSans");
574 // Set a known font description
575 FontDescriptionRun fontDescriptionRun1;
576 fontDescriptionRun1.characterRun.characterIndex = 0u;
577 fontDescriptionRun1.characterRun.numberOfCharacters = 18u;
578 fontDescriptionRun1.familyLength = fontFamily.size();
579 fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
580 memcpy(fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength);
581 fontDescriptionRun1.familyDefined = true;
582 fontDescriptionRun1.weightDefined = false;
583 fontDescriptionRun1.widthDefined = false;
584 fontDescriptionRun1.slantDefined = false;
585 fontDescriptionRun1.sizeDefined = false;
587 FontDescriptionRun fontDescriptionRun2;
588 fontDescriptionRun2.characterRun.characterIndex = 18u;
589 fontDescriptionRun2.characterRun.numberOfCharacters = 31u;
590 fontDescriptionRun2.familyLength = fontFamily.size();
591 fontDescriptionRun2.familyName = new char[fontDescriptionRun2.familyLength];
592 memcpy(fontDescriptionRun2.familyName, fontFamily.c_str(), fontDescriptionRun2.familyLength);
593 fontDescriptionRun2.familyDefined = true;
594 fontDescriptionRun2.weightDefined = false;
595 fontDescriptionRun2.widthDefined = false;
596 fontDescriptionRun2.slantDefined = false;
597 fontDescriptionRun2.sizeDefined = false;
599 Vector<FontDescriptionRun> fontDescriptionRuns;
600 fontDescriptionRuns.PushBack(fontDescriptionRun1);
601 fontDescriptionRuns.PushBack(fontDescriptionRun2);
602 Size textArea(100.f, 300.f);
603 Size layoutSize(96.f, 97.f);
606 0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f, 0.f, -13.f, 9.f, -9.f, 18.f, -9.f, 31.f, -9.f, 40.f, -2.f, 44.f, -12.f, 0.f, -12.f, 8.f, -9.f, 18.f, -9.f, 27.f, -9.f, 38.f, -9.f, 47.f, -11.f, 53.f, -0.f, 0.f, -12.f, 11.f, -12.f, 14.f, -12.f, 25.f, -9.f, 36.f, -9.f, 41.f, -9.f, 52.f, -9.f, 61.f, -11.f, 67.f, -0.f, 0.f, -12.f, 4.f, -12.f, 8.f, -9.f, 17.f, -9.f, 27.f, -9.f, 35.f, -0.f, 40.f, -9.f, 50.f, -12.f, 56.f, -0.f, 61.f, -11.f, 67.f, -9.f, 77.f, -9.f, 86.f, -11.f, 93.f, -2.f
608 struct LineRun line0 =
620 struct LineRun line1 =
632 struct LineRun line2 =
644 struct LineRun line3 =
656 struct LineRun line4 =
668 Vector<LineRun> lines;
669 lines.PushBack(line0);
670 lines.PushBack(line1);
671 lines.PushBack(line2);
672 lines.PushBack(line3);
673 lines.PushBack(line4);
675 LayoutTextData data =
677 "Layout simple multiline text",
678 "Hello world demo.\n"
679 "Layout different lines of text.",
682 fontDescriptionRuns.Begin(),
688 Layout::Engine::MULTI_LINE_BOX,
695 if(!LayoutTextTest(data))
697 tet_result(TET_FAIL);
700 tet_result(TET_PASS);
704 int UtcDaliTextCharacterSpacingMultilineText2(void)
706 ToolkitTestApplication application;
707 tet_infoline(" UtcDaliTextCharacterSpacingMultilineText2");
709 // Layout some lines of left to right text.
711 const std::string fontFamily("TizenSans");
713 // Set a known font description
714 FontDescriptionRun fontDescriptionRun1;
715 fontDescriptionRun1.characterRun.characterIndex = 0u;
716 fontDescriptionRun1.characterRun.numberOfCharacters = 18u;
717 fontDescriptionRun1.familyLength = fontFamily.size();
718 fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
719 memcpy(fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength);
720 fontDescriptionRun1.familyDefined = true;
721 fontDescriptionRun1.weightDefined = false;
722 fontDescriptionRun1.widthDefined = false;
723 fontDescriptionRun1.slantDefined = false;
724 fontDescriptionRun1.sizeDefined = false;
726 FontDescriptionRun fontDescriptionRun2;
727 fontDescriptionRun2.characterRun.characterIndex = 18u;
728 fontDescriptionRun2.characterRun.numberOfCharacters = 31u;
729 fontDescriptionRun2.familyLength = fontFamily.size();
730 fontDescriptionRun2.familyName = new char[fontDescriptionRun2.familyLength];
731 memcpy(fontDescriptionRun2.familyName, fontFamily.c_str(), fontDescriptionRun2.familyLength);
732 fontDescriptionRun2.familyDefined = true;
733 fontDescriptionRun2.weightDefined = false;
734 fontDescriptionRun2.widthDefined = false;
735 fontDescriptionRun2.slantDefined = false;
736 fontDescriptionRun2.sizeDefined = false;
738 Vector<FontDescriptionRun> fontDescriptionRuns;
739 fontDescriptionRuns.PushBack(fontDescriptionRun1);
740 fontDescriptionRuns.PushBack(fontDescriptionRun2);
741 Size textArea(100.f, 300.f);
742 Size layoutSize(99.f, 116.f);
745 0.f, -12.f, 12.f, -9.f, 23.f, -13.f, 29.f, -13.f, 34.f, -9.f, 45.f, -0.f, 51.f, -9.f, 65.f, -9.f, 77.f, -9.f, 85.f, -13.f, 90.f, -13.f, 101.f, -0.f, 0.f, -13.f, 11.f, -9.f, 22.f, -9.f, 37.f, -9.f, 48.f, -2.f, 54.f, -12.f, 0.f, -12.f, 10.f, -9.f, 22.f, -9.f, 33.f, -9.f, 46.f, -9.f, 57.f, -11.f, 65.f, -0.f, 0.f, -12.f, 13.f, -12.f, 18.f, -12.f, 31.f, -9.f, 44.f, -9.f, 51.f, -9.f, 64.f, -9.f, 75.f, -11.f, 83.f, -0.f, 0.f, -12.f, 6.f, -12.f, 12.f, -9.f, 23.f, -9.f, 35.f, -9.f, 45.f, -0.f, 52.f, -9.f, 64.f, -12.f, 72.f, -0.f, 0.f, -11.f, 8.f, -9.f, 20.f, -9.f, 31.f, -11.f, 40.f, -2.f
747 struct LineRun line0 =
759 struct LineRun line1 =
771 struct LineRun line2 =
783 struct LineRun line3 =
795 struct LineRun line4 =
807 struct LineRun line5 =
819 Vector<LineRun> lines;
820 lines.PushBack(line0);
821 lines.PushBack(line1);
822 lines.PushBack(line2);
823 lines.PushBack(line3);
824 lines.PushBack(line4);
825 lines.PushBack(line5);
827 LayoutTextData data =
829 "Layout simple multiline text",
830 "Hello world demo.\n"
831 "Layout different lines of text.",
834 fontDescriptionRuns.Begin(),
840 Layout::Engine::MULTI_LINE_BOX,
847 if(!LayoutTextTest(data))
849 tet_result(TET_FAIL);
852 tet_result(TET_PASS);