Spannable: Add BoldSpan
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / utc-Dali-Text-TextSpannable.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/devel-api/controls/text-controls/text-spannable.h>
25 #include <dali-toolkit/devel-api/text/spannable-string.h>
26 #include <dali-toolkit/devel-api/text/spans/font-span.h>
27 #include <dali-toolkit/devel-api/text/spans/foreground-color-span.h>
28 #include <dali-toolkit/devel-api/text/spans/underline-span.h>
29 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
30 #include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
31 #include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
32 #include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
33 #include <dali-toolkit/internal/text/controller/text-controller.h>
34 #include <dali-toolkit/internal/text/font-description-run.h>
35 #include <dali-toolkit/internal/text/rendering/text-typesetter.h>
36 #include <dali-toolkit/internal/text/rendering/view-model.h>
37 #include <dali-toolkit/internal/text/text-view.h>
38 #include <dali-toolkit/public-api/text/text-enumerations.h>
39 #include <toolkit-text-utils.h>
40 #include <dali-toolkit/devel-api/text/spans/character-spacing-span.h>
41 #include <dali-toolkit/devel-api/text/spans/bold-span.h>
42
43 using namespace Dali;
44 using namespace Toolkit;
45
46 namespace
47 {
48 const std::string DEFAULT_FONT_DIR("/resources/fonts");
49 const float       PIXEL_FORMAT_64_FACTOR = 64.f; ///< 64.f is used to convert from point size to 26.6 pixel format.
50 } // namespace
51
52 Text::SpannableString CreateSpannableStringForForegroundColorSpan()
53 {
54   Text::SpannableString spannableString = Text::SpannableString::New("Hello مرحبا");
55   DALI_TEST_CHECK(spannableString);
56
57   auto isAddedGreen = spannableString.AttachSpan(
58     Text::ForegroundColorSpan::New(Color::GREEN),
59     Text::Range::New(5u, 7u));
60   DALI_TEST_CHECK(isAddedGreen);
61
62   return spannableString;
63 }
64
65 Text::SpannableString CreateSpannableStringForFontSpan()
66 {
67   Text::SpannableString spannableString = Text::SpannableString::New("Hello World");
68   DALI_TEST_CHECK(spannableString);
69
70   auto isAddedFontSpan = spannableString.AttachSpan(
71     Text::FontSpan::New("TizenSans",
72                         45.0f,
73                         Dali::TextAbstraction::FontWeight::BOLD,
74                         Dali::TextAbstraction::FontWidth::SEMI_CONDENSED,
75                         Dali::TextAbstraction::FontSlant::OBLIQUE),
76     Text::Range::New(5u, 7u));
77   DALI_TEST_CHECK(isAddedFontSpan);
78
79   return spannableString;
80 }
81
82 Text::SpannableString CreateSpannableStringForUnderlineSpan()
83 {
84   Text::SpannableString spannableString = Text::SpannableString::New("Hello World");
85   DALI_TEST_CHECK(spannableString);
86
87   auto isAddedUnderlineSpan = spannableString.AttachSpan(
88     Text::UnderlineSpan::NewDashed(Color::GREEN, 5.0f, 2.0f, 3.0f),
89     Text::Range::New(5u, 7u));
90   DALI_TEST_CHECK(isAddedUnderlineSpan);
91
92   return spannableString;
93 }
94
95 Text::SpannableString CreateSpannableStringForCharacterSpacing()
96 {
97   Text::SpannableString spannableString = Text::SpannableString::New("Hello World");
98   DALI_TEST_CHECK(spannableString);
99
100   auto isCharacterSpacingSpan = spannableString.AttachSpan(
101   Text::CharacterSpacingSpan::New(5.2f),
102   Text::Range::New(5u, 7u));
103   DALI_TEST_CHECK(isCharacterSpacingSpan);
104
105   return spannableString;
106 }
107
108 Text::SpannableString CreateSpannableStringForBoldSpan()
109 {
110   Text::SpannableString spannableString = Text::SpannableString::New("Hello");
111   DALI_TEST_CHECK(spannableString);
112
113   auto boldspan = Dali::Toolkit::Text::BoldSpan::New();
114   auto isBoldSpan = spannableString.AttachSpan(boldspan,Dali::Toolkit::Text::Range::New(0u, 3u));
115   DALI_TEST_CHECK(isBoldSpan);
116
117   return spannableString;
118
119 }
120
121 void CheckColorIndices(const Text::ColorIndex* const colorIndicesBuffer,
122                        uint32_t                      numberOfIndices,
123                        std::vector<uint32_t>         indicesToCheck,
124                        std::vector<uint32_t>         expectedValues)
125 {
126   DALI_TEST_CHECK(colorIndicesBuffer);
127
128   for(uint32_t i = 0u; i < numberOfIndices; i++)
129   {
130     DALI_TEST_EQUALS(colorIndicesBuffer[indicesToCheck[i]], expectedValues[i], TEST_LOCATION);
131   }
132 }
133
134 int UtcDaliToolkitTextLabelSetSpannedText(void)
135 {
136   ToolkitTestApplication application;
137   tet_infoline(" UtcDaliToolkitTextLabelSetSpannedText");
138
139   TextLabel textLabel = TextLabel::New();
140   DALI_TEST_CHECK(textLabel);
141   application.GetScene().Add(textLabel);
142
143   Text::SpannableString spannableString = CreateSpannableStringForForegroundColorSpan();
144
145   Text::SetSpannedText(textLabel, spannableString);
146
147   application.SendNotification();
148   application.Render();
149
150   Toolkit::Internal::TextLabel& labelImpl          = GetImpl(textLabel);
151   const Text::ColorIndex* const colorIndicesBuffer = labelImpl.GetTextController()->GetTextModel()->GetColorIndices();
152
153   CheckColorIndices(colorIndicesBuffer, 4u, {0u, 5u, 7u, 10u}, {0u, 1u, 1u, 0u});
154
155   END_TEST;
156 }
157
158 int UtcDaliToolkitTextEditorSetSpannedText(void)
159 {
160   ToolkitTestApplication application;
161   tet_infoline(" UtcDaliToolkitTextEditorSetSpannedText");
162
163   TextEditor textEditor = TextEditor::New();
164   DALI_TEST_CHECK(textEditor);
165   application.GetScene().Add(textEditor);
166
167   Text::SpannableString spannableString = CreateSpannableStringForForegroundColorSpan();
168
169   Text::SetSpannedText(textEditor, spannableString);
170
171   application.SendNotification();
172   application.Render();
173
174   Toolkit::Internal::TextEditor& labelImpl          = GetImpl(textEditor);
175   const Text::ColorIndex* const  colorIndicesBuffer = labelImpl.GetTextController()->GetTextModel()->GetColorIndices();
176
177   CheckColorIndices(colorIndicesBuffer, 4u, {0u, 5u, 7u, 10u}, {0u, 1u, 1u, 0u});
178
179   END_TEST;
180 }
181
182 int UtcDaliToolkitTextFieldSetSpannedText(void)
183 {
184   ToolkitTestApplication application;
185   tet_infoline(" UtcDaliToolkitTextFieldSetSpannedText");
186
187   TextField textField = TextField::New();
188   DALI_TEST_CHECK(textField);
189   application.GetScene().Add(textField);
190
191   Text::SpannableString spannableString = CreateSpannableStringForForegroundColorSpan();
192
193   Text::SetSpannedText(textField, spannableString);
194
195   application.SendNotification();
196   application.Render();
197
198   Toolkit::Internal::TextField& labelImpl          = GetImpl(textField);
199   const Text::ColorIndex* const colorIndicesBuffer = labelImpl.GetTextController()->GetTextModel()->GetColorIndices();
200
201   CheckColorIndices(colorIndicesBuffer, 4u, {0u, 5u, 7u, 10u}, {0u, 1u, 1u, 0u});
202
203   END_TEST;
204 }
205
206 int UtcDaliToolkitTextLabelSetSpannedText_FontSpan(void)
207 {
208   ToolkitTestApplication application;
209   tet_infoline(" UtcDaliToolkitTextLabelSetSpannedText_FontSpan ");
210
211   // Load some fonts to get the same metrics on different platforms.
212   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
213   fontClient.SetDpi(96u, 96u);
214
215   char*             pathNamePtr = get_current_dir_name();
216   const std::string pathName(pathNamePtr);
217   free(pathNamePtr);
218
219   fontClient.GetFontId(pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf");
220
221   TextLabel textLabel = TextLabel::New();
222   DALI_TEST_CHECK(textLabel);
223   application.GetScene().Add(textLabel);
224
225   Text::SpannableString spannableString = CreateSpannableStringForFontSpan();
226
227   Text::SetSpannedText(textLabel, spannableString);
228
229   application.SendNotification();
230   application.Render();
231
232   Toolkit::Internal::TextLabel&               labelImpl     = GetImpl(textLabel);
233   const Vector<Dali::Toolkit::Text::FontRun>& validFontRuns = labelImpl.GetTextController()->GetTextModel()->GetFontRuns();
234
235   DALI_TEST_EQUALS(validFontRuns.Count(), 3u, TEST_LOCATION);
236
237   DALI_TEST_EQUALS(validFontRuns[0].fontId, validFontRuns[2].fontId, TEST_LOCATION);
238   DALI_TEST_NOT_EQUALS(validFontRuns[0].fontId, validFontRuns[1].fontId, Math::MACHINE_EPSILON_100, TEST_LOCATION);
239
240   DALI_TEST_EQUALS(validFontRuns[1].characterRun.characterIndex, 5u, TEST_LOCATION);
241   DALI_TEST_EQUALS(validFontRuns[1].characterRun.GetEndCharacterIndex(), 7u, TEST_LOCATION);
242   DALI_TEST_EQUALS(validFontRuns[1].isItalicRequired, true, TEST_LOCATION);
243   DALI_TEST_EQUALS(validFontRuns[1].isBoldRequired, true, TEST_LOCATION);
244
245   TextAbstraction::FontDescription spanFontDescription;
246
247   float expectedPointSize = 45.0f * PIXEL_FORMAT_64_FACTOR;
248   float fontPointSize     = fontClient.GetPointSize(validFontRuns[1].fontId);
249   DALI_TEST_EQUALS(fontPointSize, expectedPointSize, TEST_LOCATION);
250
251   const Vector<Dali::Toolkit::Text::FontDescriptionRun>& validFontDescriptionRuns = labelImpl.GetTextController()->GetTextModel()->GetFontDescriptionRuns();
252   DALI_TEST_EQUALS(validFontDescriptionRuns.Count(), 1u, TEST_LOCATION);
253   std::string familyName = validFontDescriptionRuns[0].familyName;
254
255   DALI_TEST_EQUALS(familyName, "TizenSans", TEST_LOCATION);
256   DALI_TEST_EQUALS(validFontDescriptionRuns[0].size, expectedPointSize, TEST_LOCATION);
257   DALI_TEST_EQUALS(validFontDescriptionRuns[0].weight, Dali::TextAbstraction::FontWeight::BOLD, TEST_LOCATION);
258   DALI_TEST_EQUALS(validFontDescriptionRuns[0].width, Dali::TextAbstraction::FontWidth::SEMI_CONDENSED, TEST_LOCATION);
259   DALI_TEST_EQUALS(validFontDescriptionRuns[0].slant, Dali::TextAbstraction::FontSlant::OBLIQUE, TEST_LOCATION);
260
261   END_TEST;
262 }
263
264 int UtcDaliTextModelIsSpannedTextPlaced(void)
265
266 {
267   tet_infoline(" UtcDaliTextModelIsSpannedTextPlaced");
268
269   ToolkitTestApplication application;
270
271   // Create spanned-text and set it
272   Text::SpannableString spannedText = Text::SpannableString::New("Hello مرحبا");
273   DALI_TEST_CHECK(spannedText);
274
275   // Creates a text controller.
276   Dali::Toolkit::Text::ControllerPtr         controllerTextEditor = Dali::Toolkit::Text::Controller::New();
277   const Dali::Toolkit::Text::ModelInterface* modelEditor          = controllerTextEditor->GetTextModel();
278
279   // Tests the rendering controller has been created.
280   Dali::Toolkit::Text::TypesetterPtr typesetterEditor = Dali::Toolkit::Text::Typesetter::New(controllerTextEditor->GetTextModel());
281   DALI_TEST_CHECK(typesetterEditor);
282
283   // Tests the view model has been created.
284   Dali::Toolkit::Text::ViewModel* viewModelEditor = typesetterEditor->GetViewModel();
285   DALI_TEST_CHECK(viewModelEditor);
286
287   // Configures the text controller similarly to the text-editor.
288   Dali::Toolkit::Text::ConfigureTextEditor(controllerTextEditor);
289
290   DALI_TEST_EQUALS(false, modelEditor->IsSpannedTextPlaced(), TEST_LOCATION);
291   DALI_TEST_EQUALS(false, viewModelEditor->IsSpannedTextPlaced(), TEST_LOCATION);
292
293   controllerTextEditor->SetSpannedText(spannedText);
294
295   DALI_TEST_EQUALS(true, modelEditor->IsSpannedTextPlaced(), TEST_LOCATION);
296   DALI_TEST_EQUALS(true, viewModelEditor->IsSpannedTextPlaced(), TEST_LOCATION);
297
298   // Creates a text controller.
299   Dali::Toolkit::Text::ControllerPtr         controllerTextLabel = Dali::Toolkit::Text::Controller::New();
300   const Dali::Toolkit::Text::ModelInterface* modelLabel          = controllerTextLabel->GetTextModel();
301
302   // Tests the rendering controller has been created.
303   Dali::Toolkit::Text::TypesetterPtr typesetterLabel = Dali::Toolkit::Text::Typesetter::New(controllerTextLabel->GetTextModel());
304   DALI_TEST_CHECK(typesetterLabel);
305
306   // Tests the view model has been created.
307   Dali::Toolkit::Text::ViewModel* viewModelLabel = typesetterLabel->GetViewModel();
308   DALI_TEST_CHECK(viewModelLabel);
309
310   // Configures the text controller similarly to the text-label.
311   Dali::Toolkit::Text::ConfigureTextLabel(controllerTextLabel);
312
313   DALI_TEST_EQUALS(false, modelLabel->IsSpannedTextPlaced(), TEST_LOCATION);
314   DALI_TEST_EQUALS(false, viewModelLabel->IsSpannedTextPlaced(), TEST_LOCATION);
315
316   controllerTextLabel->SetSpannedText(spannedText);
317
318   DALI_TEST_EQUALS(true, modelLabel->IsSpannedTextPlaced(), TEST_LOCATION);
319   DALI_TEST_EQUALS(true, viewModelLabel->IsSpannedTextPlaced(), TEST_LOCATION);
320
321   // Creates a text controller.
322   Dali::Toolkit::Text::ControllerPtr         controllerTextField = Dali::Toolkit::Text::Controller::New();
323   const Dali::Toolkit::Text::ModelInterface* modelField          = controllerTextField->GetTextModel();
324
325   // Tests the rendering controller has been created.
326   Dali::Toolkit::Text::TypesetterPtr typesetterField = Dali::Toolkit::Text::Typesetter::New(controllerTextField->GetTextModel());
327   DALI_TEST_CHECK(typesetterField);
328
329   // Tests the view model has been created.
330   Dali::Toolkit::Text::ViewModel* viewModelField = typesetterField->GetViewModel();
331   DALI_TEST_CHECK(viewModelField);
332
333   // Configures the text controller similarly to the text-field.
334   Dali::Toolkit::Text::ConfigureTextField(controllerTextField);
335
336   DALI_TEST_EQUALS(false, modelField->IsSpannedTextPlaced(), TEST_LOCATION);
337   DALI_TEST_EQUALS(false, viewModelField->IsSpannedTextPlaced(), TEST_LOCATION);
338
339   controllerTextField->SetSpannedText(spannedText);
340
341   DALI_TEST_EQUALS(true, modelField->IsSpannedTextPlaced(), TEST_LOCATION);
342   DALI_TEST_EQUALS(true, viewModelField->IsSpannedTextPlaced(), TEST_LOCATION);
343
344   tet_result(TET_PASS);
345
346   END_TEST;
347 }
348
349 int UtcDaliToolkitTextLabelSetSpannedText_UnderlineSpan(void)
350 {
351   ToolkitTestApplication application;
352   tet_infoline(" UtcDaliToolkitTextLabelSetSpannedText_UnderlineSpan ");
353
354   Dali::Toolkit::Text::UnderlineStyleProperties expectedProperties = {
355     Text::Underline::DASHED,
356     Color::GREEN,
357     5u,
358     2u,
359     3u,
360     true,
361     true,
362     true,
363     true,
364     true};
365
366   TextLabel textLabel = TextLabel::New();
367   DALI_TEST_CHECK(textLabel);
368   application.GetScene().Add(textLabel);
369
370   Text::SpannableString spannableString = CreateSpannableStringForUnderlineSpan();
371
372   Text::SetSpannedText(textLabel, spannableString);
373
374   application.SendNotification();
375   application.Render();
376
377   Toolkit::Internal::TextLabel& labelImpl             = GetImpl(textLabel);
378   const Text::Length            numberOfUnderlineRuns = labelImpl.GetTextController()->GetTextModel()->GetNumberOfUnderlineRuns();
379
380   DALI_TEST_EQUALS(numberOfUnderlineRuns, 1u, TEST_LOCATION);
381
382   Vector<Dali::Toolkit::Text::UnderlinedGlyphRun> underlineRuns;
383
384   underlineRuns.Resize(numberOfUnderlineRuns);
385
386   labelImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
387
388   DALI_TEST_EQUALS(underlineRuns[0].glyphRun.glyphIndex, 5u, TEST_LOCATION);
389   DALI_TEST_EQUALS(underlineRuns[0].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION);
390   DALI_TEST_CHECK(underlineRuns[0].properties == expectedProperties);
391
392   END_TEST;
393 }
394
395 int UtcDaliToolkitTextLabelSetSpannedText_CharacterSpacingSpan(void)
396 {
397   ToolkitTestApplication application;
398   tet_infoline("UtcDaliToolkitTextLabelSetSpannedText_CharacterSpacingSpan");
399
400   TextLabel textLabel = TextLabel::New();
401   DALI_TEST_CHECK(textLabel);
402   application.GetScene().Add(textLabel);
403
404   Text::SpannableString spannableString = CreateSpannableStringForCharacterSpacing();
405   Text::SetSpannedText(textLabel, spannableString);
406
407   application.SendNotification();
408   application.Render();
409
410   Toolkit::Internal::TextLabel& labelImpl   = GetImpl(textLabel);
411   const Vector<Dali::Toolkit::Text::CharacterSpacingGlyphRun> characterSpacing = labelImpl.GetTextController()->GetTextModel()->GetCharacterSpacingGlyphRuns();
412   DALI_TEST_EQUALS(1, characterSpacing.Count(), TEST_LOCATION);
413   END_TEST;
414 }
415
416 int UtcDaliToolkitTextLabelSetSpannedText_BoldSpan(void)
417 {
418   ToolkitTestApplication application;
419
420   tet_infoline("UtcDaliToolkitTextLabelSetSpannedText_BoldSpan");
421
422   TextLabel textLabel = TextLabel::New();
423
424   DALI_TEST_CHECK(textLabel);
425
426   application.GetScene().Add(textLabel);
427
428   Text::SpannableString spannableString = CreateSpannableStringForBoldSpan();
429   Text::SetSpannedText(textLabel, spannableString);
430
431   application.SendNotification();
432   application.Render();
433
434   Toolkit::Internal::TextLabel&               labelImpl  = GetImpl(textLabel);
435
436   const Vector<Text::FontRun>& validFonts = labelImpl.GetTextController()->GetTextModel()->GetFontRuns();
437
438   DALI_TEST_EQUALS(validFonts.Count(), 2, TEST_LOCATION);
439   DALI_TEST_EQUALS(validFonts[0].characterRun.characterIndex,0, TEST_LOCATION);
440   DALI_TEST_EQUALS(validFonts[0].characterRun.GetEndCharacterIndex(),3, TEST_LOCATION);
441   DALI_TEST_EQUALS(validFonts[0].isBoldRequired, true, TEST_LOCATION);
442
443   END_TEST;
444 }