Merge "Fix visual defect during text scroll" into devel/master
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / utc-Dali-Text-Shaping.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/shaper.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 function.
32 // void ShapeText( const Vector<Character>& text,
33 //                 const Vector<LineBreakInfo>& lineBreakInfo,
34 //                 const Vector<ScriptRun>& scripts,
35 //                 const Vector<FontRun>& fonts,
36 //                 CharacterIndex startCharacterIndex,
37 //                 GlyphIndex startGlyphIndex,
38 //                 Length numberOfCharacters,
39 //                 Vector<GlyphInfo>& glyphs,
40 //                 Vector<CharacterIndex>& glyphToCharacterMap,
41 //                 Vector<Length>& charactersPerGlyph,
42 //                 Vector<GlyphIndex>& newParagraphGlyphs );
43
44 //////////////////////////////////////////////////////////
45
46 namespace
47 {
48 const std::string DEFAULT_FONT_DIR("/resources/fonts");
49
50 struct GlyphInfoData
51 {
52   FontId     fontId;           ///< Identifies the font containing the glyph
53   GlyphIndex index;            ///< Uniquely identifies a glyph for a given FontId
54   float      width;            ///< The width of the glyph
55   float      height;           ///< The height of the glyph
56   float      xBearing;         ///< The distance from the cursor position to the leftmost border of the glyph
57   float      yBearing;         ///< The distance from the baseline to the topmost border of the glyph
58   float      advance;          ///< The distance to move the cursor for this glyph
59   float      scaleFactor;      ///< The scaling applied (fixed-size fonts only)
60   bool       isItalicRequired; ///< Whether the italic style is required.
61   bool       isBoldRequired;   ///< Whether the bold style is required.
62 };
63
64 bool IsEqualGlyph(const GlyphInfoData& glyphData, const GlyphInfo& glyph)
65 {
66   if(glyphData.fontId != glyph.fontId)
67   {
68     return false;
69   }
70   if(glyphData.index != glyph.index)
71   {
72     return false;
73   }
74   if(fabsf(glyphData.width - glyph.width) > Math::MACHINE_EPSILON_1000)
75   {
76     return false;
77   }
78   if(fabsf(glyphData.height - glyph.height) > Math::MACHINE_EPSILON_1000)
79   {
80     return false;
81   }
82   if(fabsf(glyphData.xBearing - glyph.xBearing) > Math::MACHINE_EPSILON_1000)
83   {
84     return false;
85   }
86   if(fabsf(glyphData.yBearing - glyph.yBearing) > Math::MACHINE_EPSILON_1000)
87   {
88     return false;
89   }
90   if(glyphData.advance >= 0.0f && fabsf(glyphData.advance - floor(glyph.advance)) > Math::MACHINE_EPSILON_1000)
91   {
92     return false;
93   }
94   if(fabsf(glyphData.scaleFactor - glyph.scaleFactor) > Math::MACHINE_EPSILON_1000)
95   {
96     return false;
97   }
98   if(glyphData.isItalicRequired != glyph.isItalicRequired)
99   {
100     return false;
101   }
102   if(glyphData.isBoldRequired != glyph.isBoldRequired)
103   {
104     return false;
105   }
106
107   return true;
108 }
109
110 struct ShapeInfoData
111 {
112   std::string                description;                        ///< Description of the test.
113   std::string                text;                               ///< input text.
114   uint32_t                   index;                              ///< The index from where to start to query the break info.
115   uint32_t                   numberOfCharacters;                 ///< The requested number of characters.
116   uint32_t                   expectedNumberOfGlyphs;             ///< The expected number of glyphs.
117   GlyphInfoData*             glyphs;                             ///< The glyphs.
118   CharacterIndex*            characterIndices;                   ///< The character index for each glyph.
119   Length*                    charactersPerGlyph;                 ///< The characters per glyph.
120   uint32_t                   expectedNumberOfNewParagraphGlyphs; ///< The expected number of glyphs.
121   GlyphIndex*                newParagraphGlyphs;                 ///< Indices to the new paragraphs glyphs.
122   bool                       markupProcessorEnabled;             //< Enable markup processor to use markup text.
123   Vector<FontDescriptionRun> fontDescriptions;                   ///< Fonts which is used for text.
124 };
125
126 bool ShapeInfoTest(const ShapeInfoData& data)
127 {
128   // 1) Create the model.
129   ModelPtr   textModel;
130   MetricsPtr metrics;
131   Size       textArea(100.f, 60.f);
132   Size       layoutSize;
133
134   const Vector<FontDescriptionRun> fontDescriptions;
135   const LayoutOptions              options;
136
137   CreateTextModel(data.text,
138                   textArea,
139                   data.fontDescriptions,
140                   options,
141                   layoutSize,
142                   textModel,
143                   metrics,
144                   data.markupProcessorEnabled,
145                   LineWrap::WORD,
146                   false,
147                   Toolkit::DevelText::EllipsisPosition::END,
148                   0.0f, // lineSpacing
149                   0.0f  // characterSpacing
150   );
151
152   LogicalModelPtr logicalModel = textModel->mLogicalModel;
153   VisualModelPtr  visualModel  = textModel->mVisualModel;
154
155   // 2) Clear the model.
156
157   Vector<GlyphInfo>&      glyphs             = visualModel->mGlyphs;
158   Vector<CharacterIndex>& glyphToCharacter   = visualModel->mGlyphsToCharacters;
159   Vector<Length>&         charactersPerGlyph = visualModel->mCharactersPerGlyph;
160   Vector<GlyphIndex>&     charactersToGlyph  = visualModel->mCharactersToGlyph;
161   Vector<Length>&         glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
162
163   // Get the glyph index.
164   GlyphIndex glyphIndex = 0u;
165   if(0u != visualModel->mCharactersToGlyph.Count())
166   {
167     glyphIndex = *(visualModel->mCharactersToGlyph.Begin() + data.index);
168
169     const CharacterIndex lastCharacterIndex = data.index + data.numberOfCharacters - 1u;
170     const Length         numberOfGlyphs     = *(visualModel->mCharactersToGlyph.Begin() + lastCharacterIndex) + *(visualModel->mGlyphsPerCharacter.Begin() + lastCharacterIndex) - glyphIndex;
171
172     // Erase the glyph info from the text model.
173     // Got from the ShapeText() function.
174     glyphs.Erase(glyphs.Begin() + glyphIndex, glyphs.Begin() + glyphIndex + numberOfGlyphs);
175     glyphToCharacter.Erase(glyphToCharacter.Begin() + glyphIndex, glyphToCharacter.Begin() + glyphIndex + numberOfGlyphs);
176     charactersPerGlyph.Erase(charactersPerGlyph.Begin() + glyphIndex, charactersPerGlyph.Begin() + glyphIndex + numberOfGlyphs);
177
178     // Got from the VisualModel::CreateCharacterToGlyphTable() and the VisualModel::CreateGlyphsPerCharacterTable() methods.
179     charactersToGlyph.Erase(charactersToGlyph.Begin() + data.index,
180                             charactersToGlyph.Begin() + data.index + data.numberOfCharacters);
181     glyphsPerCharacter.Erase(glyphsPerCharacter.Begin() + data.index,
182                              glyphsPerCharacter.Begin() + data.index + data.numberOfCharacters);
183
184     // Update the glyph to character indices.
185     for(Vector<CharacterIndex>::Iterator it    = glyphToCharacter.Begin() + glyphIndex,
186                                          endIt = glyphToCharacter.End();
187         it != endIt;
188         ++it)
189     {
190       CharacterIndex& index = *it;
191       index -= data.numberOfCharacters;
192     }
193   }
194
195   // Reset the metrics got from the model as the ShapeText() function doesn't retrieve them.
196   for(Vector<GlyphInfo>::Iterator it    = glyphs.Begin(),
197                                   endIt = glyphs.End();
198       it != endIt;
199       ++it)
200   {
201     GlyphInfo& info  = *it;
202     info.width       = 0.f;
203     info.height      = 0.f;
204     info.xBearing    = 0.f;
205     info.yBearing    = 0.f;
206     info.scaleFactor = 0.f;
207   }
208
209   // 3) Call the ShapeText() function.
210
211   Vector<GlyphIndex> newParagraphGlyphs;
212
213   ShapeText(logicalModel->mText,
214             logicalModel->mLineBreakInfo,
215             logicalModel->mScriptRuns,
216             logicalModel->mFontRuns,
217             data.index,
218             glyphIndex,
219             data.numberOfCharacters,
220             glyphs,
221             glyphToCharacter,
222             charactersPerGlyph,
223             newParagraphGlyphs);
224
225   // Clear the advance of the new paragraph glyphs.
226   for(Vector<GlyphIndex>::Iterator it    = newParagraphGlyphs.Begin(),
227                                    endIt = newParagraphGlyphs.End();
228       it != endIt;
229       ++it)
230   {
231     GlyphInfo& info = *(glyphs.Begin() + *it);
232     info.advance    = 0.f;
233   }
234
235   // 4) Compare the results.
236
237   if(data.expectedNumberOfGlyphs != glyphs.Count())
238   {
239     std::cout << "  Different number of glyphs : " << glyphs.Count() << ", expected : " << data.expectedNumberOfGlyphs << std::endl;
240     return false;
241   }
242
243   for(unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index)
244   {
245     if(!IsEqualGlyph(data.glyphs[index], glyphs[index]))
246     {
247       std::cout << "  different glyph info, index : " << index << std::endl;
248
249       const GlyphInfo& glyphInfo = glyphs[index];
250       std::cout << "            fontId : " << glyphInfo.fontId << std::endl;
251       std::cout << "             index : " << glyphInfo.index << std::endl;
252       std::cout << "             width : " << glyphInfo.width << std::endl;
253       std::cout << "            height : " << glyphInfo.height << std::endl;
254       std::cout << "          xBearing : " << glyphInfo.xBearing << std::endl;
255       std::cout << "          yBearing : " << glyphInfo.yBearing << std::endl;
256       std::cout << "           advance : " << floor(glyphInfo.advance) << std::endl;
257       std::cout << "       scaleFactor : " << glyphInfo.scaleFactor << std::endl;
258       std::cout << "  isItalicRequired : " << glyphInfo.isItalicRequired << std::endl;
259       std::cout << "    isBoldRequired : " << glyphInfo.isBoldRequired << std::endl;
260
261       std::cout << "  Expected : " << std::endl;
262       const GlyphInfoData& expectedGlyphInfo = data.glyphs[index];
263       std::cout << "            fontId : " << expectedGlyphInfo.fontId << std::endl;
264       std::cout << "             index : " << expectedGlyphInfo.index << std::endl;
265       std::cout << "             width : " << expectedGlyphInfo.width << std::endl;
266       std::cout << "            height : " << expectedGlyphInfo.height << std::endl;
267       std::cout << "          xBearing : " << expectedGlyphInfo.xBearing << std::endl;
268       std::cout << "          yBearing : " << expectedGlyphInfo.yBearing << std::endl;
269       std::cout << "           advance : " << expectedGlyphInfo.advance << std::endl;
270       std::cout << "       scaleFactor : " << expectedGlyphInfo.scaleFactor << std::endl;
271       std::cout << "  isItalicRequired : " << expectedGlyphInfo.isItalicRequired << std::endl;
272       std::cout << "    isBoldRequired : " << expectedGlyphInfo.isBoldRequired << std::endl;
273
274       return false;
275     }
276   }
277
278   for(unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index)
279   {
280     if(data.characterIndices[index] != glyphToCharacter[index])
281     {
282       std::cout << "  different character index, index : " << index << std::endl;
283       return false;
284     }
285   }
286
287   for(unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index)
288   {
289     if(data.charactersPerGlyph[index] != charactersPerGlyph[index])
290     {
291       std::cout << "  different character per glyph, index : " << index << std::endl;
292       return false;
293     }
294   }
295
296   if(data.expectedNumberOfNewParagraphGlyphs != newParagraphGlyphs.Count())
297   {
298     std::cout << "  Different number of new paragraph glyphs : " << newParagraphGlyphs.Count() << ", expected : " << data.expectedNumberOfNewParagraphGlyphs << std::endl;
299     return false;
300   }
301
302   for(unsigned int index = 0u; index < data.expectedNumberOfNewParagraphGlyphs; ++index)
303   {
304     if(data.newParagraphGlyphs[index] != newParagraphGlyphs[index])
305     {
306       std::cout << "  different new paragraph glyph, index : " << index << std::endl;
307       return false;
308     }
309   }
310
311   return true;
312 }
313
314 void LoadTextShapeFonts()
315 {
316   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
317   fontClient.SetDpi(96u, 96u);
318
319   char*             pathNamePtr = get_current_dir_name();
320   const std::string pathName(pathNamePtr);
321   free(pathNamePtr);
322
323   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf");
324   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/noto/NotoSansMalayalam-Regular.ttf");
325 }
326
327 void LoadSoftwareStylingFonts()
328 {
329   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
330   fontClient.SetDpi(96u, 96u);
331
332   char*             pathNamePtr = get_current_dir_name();
333   const std::string pathName(pathNamePtr);
334   free(pathNamePtr);
335
336   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-Regular.ttf");
337   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-Bold.ttf");
338   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-Italic.ttf");
339   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-BoldItalic.ttf");
340 }
341
342 void LoadEmojiFonts()
343 {
344   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
345   fontClient.ClearCache();
346   fontClient.SetDpi(96u, 96u);
347
348   char*             pathNamePtr = get_current_dir_name();
349   const std::string pathName(pathNamePtr);
350   free(pathNamePtr);
351
352   TextAbstraction::FontDescription fontDescriptionText;
353   fontDescriptionText.path   = "";
354   fontDescriptionText.family = "DejaVuSans";
355   fontDescriptionText.width  = TextAbstraction::FontWidth::NONE;
356   fontDescriptionText.weight = TextAbstraction::FontWeight::NORMAL;
357   fontDescriptionText.slant  = TextAbstraction::FontSlant::NONE;
358   fontClient.GetFontId(fontDescriptionText, TextAbstraction::FontClient::DEFAULT_POINT_SIZE);
359
360   TextAbstraction::FontDescription fontDescriptionEmoji;
361   fontDescriptionEmoji.path   = "";
362   fontDescriptionEmoji.family = "NotoColorEmoji";
363   fontDescriptionEmoji.width  = TextAbstraction::FontWidth::NONE;
364   fontDescriptionEmoji.weight = TextAbstraction::FontWeight::NORMAL;
365   fontDescriptionEmoji.slant  = TextAbstraction::FontSlant::NONE;
366   fontClient.GetFontId(fontDescriptionEmoji, TextAbstraction::FontClient::DEFAULT_POINT_SIZE);
367 }
368
369 } // namespace
370
371 //////////////////////////////////////////////////////////
372
373 int UtcDaliTextShape(void)
374 {
375   tet_infoline(" UtcDaliTextShape");
376
377   struct GlyphInfoData glyphs02[] =
378     {
379       {1u, 276u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f},
380       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
381       {1u, 306u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
382       {1u, 306u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
383       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
384       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
385       {1u, 317u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f},
386       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
387       {1u, 312u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f},
388       {1u, 306u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
389       {1u, 298u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
390     };
391
392   CharacterIndex characterIndices02[]   = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u};
393   Length         charactersPerGlyph02[] = {1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u};
394
395   struct GlyphInfoData glyphs03[] =
396     {
397       {1u, 276u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f},
398       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
399       {1u, 306u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
400       {1u, 306u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
401       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
402       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
403       {1u, 317u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f},
404       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
405       {1u, 312u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f},
406       {1u, 306u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
407       {1u, 298u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
408       {1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
409       {1u, 298u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
410       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
411       {1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f},
412       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
413       {1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
414     };
415
416   CharacterIndex characterIndices03[]   = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u};
417   Length         charactersPerGlyph03[] = {1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u};
418   CharacterIndex newParagraphGlyphs03[] = {11u, 16u};
419
420   struct GlyphInfoData glyphs04[] =
421     {
422       {2u, 67u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
423       {2u, 27u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f},
424       {2u, 59u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
425       {2u, 67u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
426       {2u, 55u, 0.f, 0.f, 0.f, 0.f, 19.f, 0.f},
427       {2u, 59u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
428       {2u, 67u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
429       {2u, 56u, 0.f, 0.f, 0.f, 0.f, 19.f, 0.f},
430       {2u, 59u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
431       {2u, 67u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
432       {2u, 52u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f},
433       {2u, 59u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
434     };
435
436   CharacterIndex characterIndices04[]   = {0u, 0u, 0u, 2u, 2u, 2u, 4u, 4u, 4u, 6u, 6u, 6u};
437   Length         charactersPerGlyph04[] = {0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u};
438
439   struct GlyphInfoData glyphs05[] =
440     {
441       {1u, 280u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
442       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
443       {1u, 312u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f},
444       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
445       {1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f},
446       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
447       {1u, 303u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
448       {1u, 310u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
449       {1u, 313u, 0.f, 0.f, 0.f, 0.f, 7.f, 0.f},
450       {1u, 315u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
451       {1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f},
452       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
453       {1u, 298u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
454       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
455       {1u, 306u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
456       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
457       {1u, 312u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f},
458       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
459       {1u, 313u, 0.f, 0.f, 0.f, 0.f, 7.f, 0.f},
460       {1u, 303u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
461       {1u, 314u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f},
462       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
463       {1u, 295u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
464       {1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f},
465       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
466       {1u, 314u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f},
467       {1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
468       {1u, 295u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
469       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
470       {1u, 311u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
471       {1u, 315u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
472       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
473       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
474       {1u, 298u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
475       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
476       {1u, 403u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
477       {1u, 308u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
478       {1u, 303u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
479       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
480       {1u, 296u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
481       {1u, 295u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
482       {1u, 313u, 0.f, 0.f, 0.f, 0.f, 7.f, 0.f},
483       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
484       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
485       {1u, 295u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
486       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
487       {1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f},
488       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
489       {1u, 303u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
490       {1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
491       {1u, 310u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
492       {1u, 309u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
493       {1u, 313u, 0.f, 0.f, 0.f, 0.f, 7.f, 0.f},
494       {1u, 313u, 0.f, 0.f, 0.f, 0.f, 7.f, 0.f},
495       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
496       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
497       {1u, 303u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
498       {1u, 312u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f},
499       {1u, 295u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
500       {1u, 297u, 0.f, 0.f, 0.f, 0.f, 7.f, 0.f},
501       {1u, 315u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
502       {1u, 308u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
503       {1u, 298u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
504       {1u, 303u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
505       {1u, 295u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
506       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
507       {1u, 308u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f},
508       {1u, 299u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
509       {1u, 3u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f},
510       {1u, 297u, 0.f, 0.f, 0.f, 0.f, 7.f, 0.f},
511       {1u, 315u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f},
512       {1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f},
513       {1u, 4u, 0.f, 0.f, 0.f, 0.f, 3.f, 0.f},
514       {1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
515     };
516
517   CharacterIndex characterIndices05[]   = {0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 37u, 38u, 39u, 40u, 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 66u, 67u, 68u, 69u, 70u, 71u, 72u, 73u, 74u};
518   Length         charactersPerGlyph05[] = {1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 2u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u};
519   CharacterIndex newParagraphGlyphs05[] = {26u};
520   CharacterIndex newParagraphGlyphs06[] = {49u};
521   CharacterIndex newParagraphGlyphs07[] = {73u};
522
523   Vector<FontDescriptionRun> fontDescriptions01;
524   Vector<FontDescriptionRun> fontDescriptions02;
525   Vector<FontDescriptionRun> fontDescriptions03;
526   Vector<FontDescriptionRun> fontDescriptions04;
527   Vector<FontDescriptionRun> fontDescriptions05;
528   Vector<FontDescriptionRun> fontDescriptions06;
529
530   const std::string fontFamily("TizenSans");
531   const std::string fontFamilyMalayalam("Noto Sans Malayalam");
532
533   FontDescriptionRun fontDescriptionRun01 =
534     {
535       {0u,
536        11u},
537       nullptr,
538       0u,
539       TextAbstraction::FontWeight::NONE,
540       TextAbstraction::FontWidth::NONE,
541       TextAbstraction::FontSlant::NONE,
542       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
543       true,
544       false,
545       false,
546       false,
547       false};
548   fontDescriptionRun01.familyLength = fontFamily.size();
549   fontDescriptionRun01.familyName   = new char[fontDescriptionRun01.familyLength];
550   memcpy(fontDescriptionRun01.familyName, fontFamily.c_str(), fontDescriptionRun01.familyLength);
551
552   fontDescriptions01.PushBack(fontDescriptionRun01);
553
554   FontDescriptionRun fontDescriptionRun02 =
555     {
556       {0u,
557        17u},
558       nullptr,
559       0u,
560       TextAbstraction::FontWeight::NONE,
561       TextAbstraction::FontWidth::NONE,
562       TextAbstraction::FontSlant::NONE,
563       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
564       true,
565       false,
566       false,
567       false,
568       false};
569   fontDescriptionRun02.familyLength = fontFamily.size();
570   fontDescriptionRun02.familyName   = new char[fontDescriptionRun02.familyLength];
571   memcpy(fontDescriptionRun02.familyName, fontFamily.c_str(), fontDescriptionRun02.familyLength);
572
573   fontDescriptions02.PushBack(fontDescriptionRun02);
574
575   FontDescriptionRun fontDescriptionRun03 =
576     {
577       {0u,
578        8u},
579       nullptr,
580       0u,
581       TextAbstraction::FontWeight::NONE,
582       TextAbstraction::FontWidth::NONE,
583       TextAbstraction::FontSlant::NONE,
584       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
585       true,
586       false,
587       false,
588       false,
589       false};
590   fontDescriptionRun03.familyLength = fontFamilyMalayalam.size();
591   fontDescriptionRun03.familyName   = new char[fontDescriptionRun03.familyLength];
592   memcpy(fontDescriptionRun03.familyName, fontFamilyMalayalam.c_str(), fontDescriptionRun03.familyLength);
593
594   fontDescriptions03.PushBack(fontDescriptionRun03);
595
596   FontDescriptionRun fontDescriptionRun04 =
597     {
598       {0u,
599        75u},
600       nullptr,
601       0u,
602       TextAbstraction::FontWeight::NONE,
603       TextAbstraction::FontWidth::NONE,
604       TextAbstraction::FontSlant::NONE,
605       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
606       true,
607       false,
608       false,
609       false,
610       false};
611   fontDescriptionRun04.familyLength = fontFamily.size();
612   fontDescriptionRun04.familyName   = new char[fontDescriptionRun04.familyLength];
613   memcpy(fontDescriptionRun04.familyName, fontFamily.c_str(), fontDescriptionRun04.familyLength);
614
615   fontDescriptions04.PushBack(fontDescriptionRun04);
616
617   FontDescriptionRun fontDescriptionRun05 =
618     {
619       {0u,
620        75u},
621       nullptr,
622       0u,
623       TextAbstraction::FontWeight::NONE,
624       TextAbstraction::FontWidth::NONE,
625       TextAbstraction::FontSlant::NONE,
626       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
627       true,
628       false,
629       false,
630       false,
631       false};
632   fontDescriptionRun05.familyLength = fontFamily.size();
633   fontDescriptionRun05.familyName   = new char[fontDescriptionRun05.familyLength];
634   memcpy(fontDescriptionRun05.familyName, fontFamily.c_str(), fontDescriptionRun05.familyLength);
635
636   fontDescriptions05.PushBack(fontDescriptionRun05);
637
638   FontDescriptionRun fontDescriptionRun06 =
639     {
640       {0u,
641        75u},
642       nullptr,
643       0u,
644       TextAbstraction::FontWeight::NONE,
645       TextAbstraction::FontWidth::NONE,
646       TextAbstraction::FontSlant::NONE,
647       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
648       true,
649       false,
650       false,
651       false,
652       false};
653   fontDescriptionRun06.familyLength = fontFamily.size();
654   fontDescriptionRun06.familyName   = new char[fontDescriptionRun06.familyLength];
655   memcpy(fontDescriptionRun06.familyName, fontFamily.c_str(), fontDescriptionRun06.familyLength);
656
657   fontDescriptions06.PushBack(fontDescriptionRun06);
658
659   struct ShapeInfoData data[] =
660     {
661       {
662         "Zero characters",
663         "",
664         0u,
665         0u,
666         0u,
667         nullptr,
668         nullptr,
669         nullptr,
670         0u,
671         nullptr,
672         false,
673       },
674       {"Latin script",
675        "Hello world",
676        0u,
677        11u,
678        11u,
679        glyphs02,
680        characterIndices02,
681        charactersPerGlyph02,
682        0u,
683        nullptr,
684        false,
685        fontDescriptions01},
686       {"Latin script. Some paragraphs.",
687        "Hello world\ndemo\n",
688        0u,
689        17u,
690        17u,
691        glyphs03,
692        characterIndices03,
693        charactersPerGlyph03,
694        2u,
695        newParagraphGlyphs03,
696        false,
697        fontDescriptions02},
698       {"Malayalam script. More glyphs than characters.",
699        "ജോസോഹോവോ",
700        0u,
701        8u,
702        12u,
703        glyphs04,
704        characterIndices04,
705        charactersPerGlyph04,
706        0u,
707        nullptr,
708        false,
709        fontDescriptions03},
710       {
711         "Latin script with some paragraphs. Update initial paragraph.",
712         "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
713         0u,
714         27u,
715         74u,
716         glyphs05,
717         characterIndices05,
718         charactersPerGlyph05,
719         1u,
720         newParagraphGlyphs05,
721         false,
722         fontDescriptions04,
723       },
724       {"Latin script with some paragraphs. Update mid paragraph.",
725        "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
726        27u,
727        24u,
728        74u,
729        glyphs05,
730        characterIndices05,
731        charactersPerGlyph05,
732        1u,
733        newParagraphGlyphs06,
734        false,
735        fontDescriptions05},
736       {"Latin script with some paragraphs. Update final paragraph.",
737        "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
738        51u,
739        24u,
740        74u,
741        glyphs05,
742        characterIndices05,
743        charactersPerGlyph05,
744        1u,
745        newParagraphGlyphs07,
746        false,
747        fontDescriptions06},
748     };
749   const unsigned int numberOfTests = 7u;
750
751   for(unsigned int index = 0u; index < numberOfTests; ++index)
752   {
753     ToolkitTestApplication application;
754     LoadTextShapeFonts();
755
756     if(!ShapeInfoTest(data[index]))
757     {
758       tet_result(TET_FAIL);
759     }
760   }
761
762   tet_result(TET_PASS);
763   END_TEST;
764 }
765
766 int UtcDaliTextSoftwareStyling(void)
767 {
768   tet_infoline(" UtcDaliTextSoftwareStyling");
769
770   struct GlyphInfoData glyphs01[] =
771     {
772       {4u, 38u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, true},
773       {4u, 39u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f, true, true},
774       {4u, 40u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, true},
775       {4u, 41u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, true},
776     };
777   struct GlyphInfoData glyphs02[] =
778     {
779       {1u, 38u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, false, false},
780       {2u, 39u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, false, true},
781       {3u, 40u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, false},
782       {4u, 41u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, true},
783     };
784
785   CharacterIndex characterIndices[]   = {0u, 1u, 2u, 3u};
786   Length         charactersPerGlyph[] = {1u, 1u, 1u, 1u};
787
788   Vector<FontDescriptionRun> fontDescriptions01;
789   Vector<FontDescriptionRun> fontDescriptions02;
790
791   const std::string fontFamily("Roboto");
792
793   FontDescriptionRun fontDescriptionRun01 =
794     {
795       {0u,
796        4u},
797       nullptr,
798       0u,
799       TextAbstraction::FontWeight::BOLD,
800       TextAbstraction::FontWidth::NONE,
801       TextAbstraction::FontSlant::ITALIC,
802       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
803       true,
804       true,
805       false,
806       true,
807       false};
808   fontDescriptionRun01.familyLength = fontFamily.size();
809   fontDescriptionRun01.familyName   = new char[fontDescriptionRun01.familyLength];
810   memcpy(fontDescriptionRun01.familyName, fontFamily.c_str(), fontDescriptionRun01.familyLength);
811
812   fontDescriptions01.PushBack(fontDescriptionRun01);
813
814   FontDescriptionRun fontDescriptionRun02 =
815     {
816       {0u,
817        1u},
818       nullptr,
819       0u,
820       TextAbstraction::FontWeight::NONE,
821       TextAbstraction::FontWidth::NONE,
822       TextAbstraction::FontSlant::NONE,
823       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
824       true,
825       false,
826       false,
827       false,
828       false};
829   fontDescriptionRun02.familyLength = fontFamily.size();
830   fontDescriptionRun02.familyName   = new char[fontDescriptionRun02.familyLength];
831   memcpy(fontDescriptionRun02.familyName, fontFamily.c_str(), fontDescriptionRun02.familyLength);
832
833   FontDescriptionRun fontDescriptionRun03 =
834     {
835       {1u,
836        1u},
837       nullptr,
838       0u,
839       TextAbstraction::FontWeight::BOLD,
840       TextAbstraction::FontWidth::NONE,
841       TextAbstraction::FontSlant::NONE,
842       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
843       true,
844       true,
845       false,
846       false,
847       false};
848   fontDescriptionRun03.familyLength = fontFamily.size();
849   fontDescriptionRun03.familyName   = new char[fontDescriptionRun03.familyLength];
850   memcpy(fontDescriptionRun03.familyName, fontFamily.c_str(), fontDescriptionRun03.familyLength);
851
852   FontDescriptionRun fontDescriptionRun04 =
853     {
854       {2u,
855        1u},
856       nullptr,
857       0u,
858       TextAbstraction::FontWeight::NONE,
859       TextAbstraction::FontWidth::NONE,
860       TextAbstraction::FontSlant::ITALIC,
861       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
862       true,
863       false,
864       false,
865       true,
866       false};
867   fontDescriptionRun04.familyLength = fontFamily.size();
868   fontDescriptionRun04.familyName   = new char[fontDescriptionRun04.familyLength];
869   memcpy(fontDescriptionRun04.familyName, fontFamily.c_str(), fontDescriptionRun04.familyLength);
870
871   FontDescriptionRun fontDescriptionRun05 =
872     {
873       {3u,
874        1u},
875       nullptr,
876       0u,
877       TextAbstraction::FontWeight::BOLD,
878       TextAbstraction::FontWidth::NONE,
879       TextAbstraction::FontSlant::ITALIC,
880       TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
881       true,
882       true,
883       false,
884       true,
885       false};
886   fontDescriptionRun05.familyLength = fontFamily.size();
887   fontDescriptionRun05.familyName   = new char[fontDescriptionRun05.familyLength];
888   memcpy(fontDescriptionRun05.familyName, fontFamily.c_str(), fontDescriptionRun05.familyLength);
889
890   fontDescriptions02.PushBack(fontDescriptionRun02);
891   fontDescriptions02.PushBack(fontDescriptionRun03);
892   fontDescriptions02.PushBack(fontDescriptionRun04);
893   fontDescriptions02.PushBack(fontDescriptionRun05);
894
895   struct ShapeInfoData data[] =
896     {
897       {"Latin script. Characters have same font description",
898        "ABCD",
899        0u,
900        4u,
901        4u,
902        glyphs01,
903        characterIndices,
904        charactersPerGlyph,
905        0u,
906        nullptr,
907        false,
908        fontDescriptions01},
909       {"Latin script. Each character has different font description.",
910        "ABCD",
911        0u,
912        4u,
913        4u,
914        glyphs02,
915        characterIndices,
916        charactersPerGlyph,
917        0u,
918        nullptr,
919        false,
920        fontDescriptions02}};
921
922   const unsigned int numberOfTests = 2u;
923
924   for(unsigned int index = 0u; index < numberOfTests; ++index)
925   {
926     ToolkitTestApplication application;
927     LoadSoftwareStylingFonts();
928
929     if(!ShapeInfoTest(data[index]))
930     {
931       tet_result(TET_FAIL);
932     }
933   }
934
935   tet_result(TET_PASS);
936   END_TEST;
937 }
938
939 int UtcDaliTextShapeEmojiSequences(void)
940 {
941   ToolkitTestApplication application;
942
943   tet_infoline(" UtcDaliTextShapeEmojiSequences");
944
945   const std::string colorFontFamily("NotoColorEmoji");
946   const std::string textFontFamily("DejaVuSans");
947
948   LoadEmojiFonts();
949
950   //Common attributes for font Descriptions
951   CharacterRun    characterRun = {0u, 2u};
952   FontWeight      weight       = TextAbstraction::FontWeight::NORMAL;
953   FontWidth       width        = TextAbstraction::FontWidth::NORMAL;
954   FontSlant       slant        = TextAbstraction::FontSlant::ITALIC;
955   PointSize26Dot6 size         = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
956
957   bool familyDefined = true;
958   bool weightDefined = false;
959   bool widthDefined  = false;
960   bool slantDefined  = false;
961   bool sizeDefined   = false;
962
963   // variation selector 16 (Emoji)
964   // Note : Non-scalable font's advance value is undefined. See https://github.com/harfbuzz/harfbuzz/discussions/3023. 2022-06-03 updated.
965   struct GlyphInfoData glyphsVS16[] =
966     {
967       {2u, 74u, 0.f, 0.f, 0.f, 0.f, -1.0f /* Special value that we don't check it */, 0.f, false, false},
968     };
969   CharacterIndex characterIndicesVS16[]   = {0u, 1u};
970   Length         charactersPerGlyphVS16[] = {2u};
971
972   // variation selector 15 (Text)
973   struct GlyphInfoData glyphsVS15[] =
974     {
975       {1u, 3842u, 0.f, 0.f, 0.f, 0.f, 14.0f, 0.f, false, false},
976       {1u, 8203u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, false, false},
977     };
978   CharacterIndex characterIndicesVS15[]   = {0u, 0u};
979   Length         charactersPerGlyphVS15[] = {0u, 2u};
980
981   //Font Descriptions
982   Vector<FontDescriptionRun> fontDescriptionsColorVS16 =
983     CreateSingleFontDescription(characterRun, colorFontFamily, weight, width, slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined);
984
985   Vector<FontDescriptionRun> fontDescriptionsColorVS15 =
986     CreateSingleFontDescription(characterRun, colorFontFamily, weight, width, slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined);
987
988   Vector<FontDescriptionRun> fontDescriptionsTextVS16 =
989     CreateSingleFontDescription(characterRun, textFontFamily, weight, width, slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined);
990
991   Vector<FontDescriptionRun> fontDescriptionsTextVS15 =
992     CreateSingleFontDescription(characterRun, textFontFamily, weight, width, slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined);
993
994   struct ShapeInfoData data[] =
995     {
996       {"EMOJI Sequence: Color Font with VS16",
997        "&#x262a;&#xfe0f;",
998        0u,
999        2u,
1000        1u,
1001        glyphsVS16,
1002        characterIndicesVS16,
1003        charactersPerGlyphVS16,
1004        0u,
1005        nullptr,
1006        true,
1007        fontDescriptionsColorVS16},
1008       {"EMOJI Sequence: Color Font with VS15",
1009        "&#x262a;&#xfe0e;",
1010        0u,
1011        2u,
1012        2u,
1013        glyphsVS15,
1014        characterIndicesVS15,
1015        charactersPerGlyphVS15,
1016        0u,
1017        nullptr,
1018        true,
1019        fontDescriptionsColorVS15},
1020       {"EMOJI Sequence: Text Font with VS16",
1021        "&#x262a;&#xfe0f;",
1022        0u,
1023        2u,
1024        1u,
1025        glyphsVS16,
1026        characterIndicesVS16,
1027        charactersPerGlyphVS16,
1028        0u,
1029        nullptr,
1030        true,
1031        fontDescriptionsTextVS16},
1032       {"EMOJI Sequence: Text Font with VS15",
1033        "&#x262a;&#xfe0e;",
1034        0u,
1035        2u,
1036        2u,
1037        glyphsVS15,
1038        characterIndicesVS15,
1039        charactersPerGlyphVS15,
1040        0u,
1041        nullptr,
1042        true,
1043        fontDescriptionsTextVS15},
1044     };
1045
1046   const unsigned int numberOfTests = 4u;
1047
1048   for(unsigned int index = 0u; index < numberOfTests; ++index)
1049   {
1050     tet_infoline(data[index].description.c_str());
1051     if(!ShapeInfoTest(data[index]))
1052     {
1053       tet_result(TET_FAIL);
1054     }
1055   }
1056
1057   tet_result(TET_PASS);
1058   END_TEST;
1059 }