Updated all cpp files to new format
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / logical-model-impl.cpp
1 /*
2  * Copyright (c) 2021 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 // CLASS HEADER
19 #include <dali-toolkit/internal/text/logical-model-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/text/input-style.h>
23 #include <dali-toolkit/internal/text/text-run-container.h>
24
25 namespace Dali
26 {
27 namespace Toolkit
28 {
29 namespace Text
30 {
31 void FreeFontFamilyNames(Vector<FontDescriptionRun>& fontDescriptionRuns)
32 {
33   for(Vector<FontDescriptionRun>::Iterator it    = fontDescriptionRuns.Begin(),
34                                            endIt = fontDescriptionRuns.End();
35       it != endIt;
36       ++it)
37   {
38     delete[](*it).familyName;
39   }
40
41   fontDescriptionRuns.Clear();
42 }
43
44 void FreeEmbeddedItems(Vector<EmbeddedItem>& embeddedItem)
45 {
46   for(Vector<EmbeddedItem>::Iterator it    = embeddedItem.Begin(),
47                                      endIt = embeddedItem.End();
48       it != endIt;
49       ++it)
50   {
51     EmbeddedItem& item = *it;
52     delete[] item.url;
53   }
54
55   embeddedItem.Clear();
56 }
57
58 LogicalModelPtr LogicalModel::New()
59 {
60   return LogicalModelPtr(new LogicalModel());
61 }
62
63 Script LogicalModel::GetScript(CharacterIndex characterIndex) const
64 {
65   // If this operation is too slow, consider a binary search.
66
67   const ScriptRun* const scriptRunBuffer = mScriptRuns.Begin();
68   for(Length index = 0u, length = mScriptRuns.Count(); index < length; ++index)
69   {
70     const ScriptRun* const scriptRun = scriptRunBuffer + index;
71
72     if((scriptRun->characterRun.characterIndex <= characterIndex) &&
73        (characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters))
74     {
75       return scriptRun->script;
76     }
77   }
78
79   return TextAbstraction::UNKNOWN;
80 }
81
82 CharacterDirection LogicalModel::GetCharacterDirection(CharacterIndex characterIndex) const
83 {
84   if(characterIndex >= mCharacterDirections.Count())
85   {
86     // The model has no right to left characters, so the vector of directions is void.
87     return false;
88   }
89
90   return *(mCharacterDirections.Begin() + characterIndex);
91 }
92
93 CharacterIndex LogicalModel::GetLogicalCursorIndex(CharacterIndex visualCursorIndex)
94 {
95   // The character's directions buffer.
96   const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
97
98   // The bidirectional line info.
99   const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
100
101   // Whether the paragraph starts with a right to left character.
102   const bool isRightToLeftParagraph = bidirectionalLineInfo->direction;
103
104   // The total number of characters of the line.
105   const Length lastCharacterIndex = bidirectionalLineInfo->characterRun.characterIndex + bidirectionalLineInfo->characterRun.numberOfCharacters;
106
107   CharacterIndex logicalCursorIndex = 0u;
108
109   if(bidirectionalLineInfo->characterRun.characterIndex == visualCursorIndex)
110   {
111     if(isRightToLeftParagraph)
112     {
113       logicalCursorIndex = lastCharacterIndex;
114     }
115     else // else logical position is the first of the line.
116     {
117       logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
118     }
119   }
120   else if(lastCharacterIndex == visualCursorIndex)
121   {
122     if(isRightToLeftParagraph)
123     {
124       logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
125     }
126     else // else logical position is the number of characters.
127     {
128       logicalCursorIndex = lastCharacterIndex;
129     }
130   }
131   else
132   {
133     // Get the character indexed by  index - 1 and index
134     // and calculate the logical position according the directions of
135     // both characters and the direction of the paragraph.
136
137     const CharacterIndex previousVisualCursorIndex  = visualCursorIndex - 1u;
138     const CharacterIndex previousLogicalCursorIndex = *(bidirectionalLineInfo->visualToLogicalMap + previousVisualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
139     const CharacterIndex currentLogicalCursorIndex  = *(bidirectionalLineInfo->visualToLogicalMap + visualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
140
141     const CharacterDirection previousCharacterDirection = *(modelCharacterDirections + previousLogicalCursorIndex);
142     const CharacterDirection currentCharacterDirection  = *(modelCharacterDirections + currentLogicalCursorIndex);
143
144     if(previousCharacterDirection == currentCharacterDirection)
145     {
146       // Both glyphs have the same direction.
147       if(previousCharacterDirection)
148       {
149         logicalCursorIndex = previousLogicalCursorIndex;
150       }
151       else
152       {
153         logicalCursorIndex = currentLogicalCursorIndex;
154       }
155     }
156     else
157     {
158       if(isRightToLeftParagraph)
159       {
160         if(currentCharacterDirection)
161         {
162           logicalCursorIndex = currentLogicalCursorIndex + 1u;
163         }
164         else
165         {
166           logicalCursorIndex = previousLogicalCursorIndex;
167         }
168       }
169       else
170       {
171         if(previousCharacterDirection)
172         {
173           logicalCursorIndex = currentLogicalCursorIndex;
174         }
175         else
176         {
177           logicalCursorIndex = previousLogicalCursorIndex + 1u;
178         }
179       }
180     }
181   }
182
183   return logicalCursorIndex;
184 }
185
186 CharacterIndex LogicalModel::GetLogicalCharacterIndex(CharacterIndex visualCharacterIndex)
187 {
188   // The bidirectional line info.
189   const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
190
191   return *(bidirectionalLineInfo->visualToLogicalMap + visualCharacterIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
192 }
193
194 bool LogicalModel::FetchBidirectionalLineInfo(CharacterIndex characterIndex)
195 {
196   // The number of bidirectional lines.
197   const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count();
198
199   if(0u == numberOfBidirectionalLines)
200   {
201     // If there is no bidirectional info.
202     return false;
203   }
204
205   // Find the bidi line where the character is laid-out.
206
207   const BidirectionalLineInfoRun* const bidirectionalLineInfoBuffer = mBidirectionalLineInfo.Begin();
208
209   // Check first if the character is in the previously fetched line.
210
211   BidirectionalLineRunIndex bidiLineIndex                 = 0u;
212   CharacterIndex            lastCharacterOfRightToLeftRun = 0u;
213   if(mBidirectionalLineIndex < numberOfBidirectionalLines)
214   {
215     const BidirectionalLineInfoRun& bidiLineRun = *(bidirectionalLineInfoBuffer + mBidirectionalLineIndex);
216
217     const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
218     if((bidiLineRun.characterRun.characterIndex <= characterIndex) &&
219        (characterIndex < lastCharacterOfRunPlusOne))
220     {
221       // The character is in the previously fetched bidi line.
222       return true;
223     }
224     else
225     {
226       // The character is not in the previously fetched line.
227       // Set the bidi line index from where to start the fetch.
228
229       if(characterIndex < bidiLineRun.characterRun.characterIndex)
230       {
231         // Start the fetch from the beginning.
232         bidiLineIndex = 0u;
233       }
234       else
235       {
236         // Start the fetch from the next line.
237         bidiLineIndex                 = mBidirectionalLineIndex + 1u;
238         lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
239       }
240     }
241   }
242
243   // The character has not been found in the previously fetched bidi line.
244   for(Vector<BidirectionalLineInfoRun>::ConstIterator it    = bidirectionalLineInfoBuffer + bidiLineIndex,
245                                                       endIt = mBidirectionalLineInfo.End();
246       it != endIt;
247       ++it, ++bidiLineIndex)
248   {
249     const BidirectionalLineInfoRun& bidiLineRun = *it;
250
251     if((lastCharacterOfRightToLeftRun < characterIndex) &&
252        (characterIndex < bidiLineRun.characterRun.characterIndex))
253     {
254       // The character is not inside a bidi line.
255       return false;
256     }
257
258     const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
259     lastCharacterOfRightToLeftRun                  = lastCharacterOfRunPlusOne - 1u;
260     if((bidiLineRun.characterRun.characterIndex <= characterIndex) &&
261        (characterIndex < lastCharacterOfRunPlusOne))
262     {
263       // Bidi line found. Fetch the line.
264       mBidirectionalLineIndex = bidiLineIndex;
265       return true;
266     }
267   }
268
269   return false;
270 }
271
272 BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const
273 {
274   return mBidirectionalLineIndex;
275 }
276
277 void LogicalModel::UpdateTextStyleRuns(CharacterIndex index, int numberOfCharacters)
278 {
279   const Length totalNumberOfCharacters = mText.Count();
280
281   // Process the color runs.
282   Vector<ColorRun> removedColorRuns;
283   UpdateCharacterRuns<ColorRun>(index,
284                                 numberOfCharacters,
285                                 totalNumberOfCharacters,
286                                 mColorRuns,
287                                 removedColorRuns);
288
289   // Process the background color runs.
290   Vector<ColorRun> removedBackgroundColorRuns;
291   UpdateCharacterRuns<ColorRun>(index,
292                                 numberOfCharacters,
293                                 totalNumberOfCharacters,
294                                 mBackgroundColorRuns,
295                                 removedBackgroundColorRuns);
296
297   // Process the font description runs.
298   Vector<FontDescriptionRun> removedFontDescriptionRuns;
299   UpdateCharacterRuns<FontDescriptionRun>(index,
300                                           numberOfCharacters,
301                                           totalNumberOfCharacters,
302                                           mFontDescriptionRuns,
303                                           removedFontDescriptionRuns);
304
305   // Free memory allocated for the font family name.
306   FreeFontFamilyNames(removedFontDescriptionRuns);
307 }
308
309 void LogicalModel::RetrieveStyle(CharacterIndex index, InputStyle& style)
310 {
311   unsigned int runIndex = 0u;
312
313   // Set the text color.
314   bool                  colorOverriden  = false;
315   unsigned int          colorIndex      = 0u;
316   const ColorRun* const colorRunsBuffer = mColorRuns.Begin();
317   for(Vector<ColorRun>::ConstIterator it    = colorRunsBuffer,
318                                       endIt = mColorRuns.End();
319       it != endIt;
320       ++it, ++runIndex)
321   {
322     const ColorRun& colorRun = *it;
323
324     if((colorRun.characterRun.characterIndex <= index) &&
325        (index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters))
326     {
327       colorIndex     = runIndex;
328       colorOverriden = true;
329     }
330   }
331
332   // Set the text's color if it's overriden.
333   if(colorOverriden)
334   {
335     style.textColor      = (*(colorRunsBuffer + colorIndex)).color;
336     style.isDefaultColor = false;
337   }
338
339   // Reset the run index.
340   runIndex = 0u;
341
342   // Set the font's parameters.
343   bool                            nameOverriden             = false;
344   bool                            weightOverriden           = false;
345   bool                            widthOverriden            = false;
346   bool                            slantOverriden            = false;
347   bool                            sizeOverriden             = false;
348   unsigned int                    nameIndex                 = 0u;
349   unsigned int                    weightIndex               = 0u;
350   unsigned int                    widthIndex                = 0u;
351   unsigned int                    slantIndex                = 0u;
352   unsigned int                    sizeIndex                 = 0u;
353   const FontDescriptionRun* const fontDescriptionRunsBuffer = mFontDescriptionRuns.Begin();
354   for(Vector<FontDescriptionRun>::ConstIterator it    = fontDescriptionRunsBuffer,
355                                                 endIt = mFontDescriptionRuns.End();
356       it != endIt;
357       ++it, ++runIndex)
358   {
359     const FontDescriptionRun& fontDescriptionRun = *it;
360
361     if((fontDescriptionRun.characterRun.characterIndex <= index) &&
362        (index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters))
363     {
364       if(fontDescriptionRun.familyDefined)
365       {
366         nameIndex     = runIndex;
367         nameOverriden = true;
368       }
369
370       if(fontDescriptionRun.weightDefined)
371       {
372         weightIndex     = runIndex;
373         weightOverriden = true;
374       }
375
376       if(fontDescriptionRun.widthDefined)
377       {
378         widthIndex     = runIndex;
379         widthOverriden = true;
380       }
381
382       if(fontDescriptionRun.slantDefined)
383       {
384         slantIndex     = runIndex;
385         slantOverriden = true;
386       }
387
388       if(fontDescriptionRun.sizeDefined)
389       {
390         sizeIndex     = runIndex;
391         sizeOverriden = true;
392       }
393     }
394   }
395
396   // Set the font's family name if it's overriden.
397   if(nameOverriden)
398   {
399     const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + nameIndex);
400
401     style.familyName      = std::string(fontDescriptionRun.familyName, fontDescriptionRun.familyLength);
402     style.isFamilyDefined = true;
403   }
404
405   // Set the font's weight if it's overriden.
406   if(weightOverriden)
407   {
408     const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + weightIndex);
409
410     style.weight          = fontDescriptionRun.weight;
411     style.isWeightDefined = true;
412   }
413
414   // Set the font's width if it's overriden.
415   if(widthOverriden)
416   {
417     const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + widthIndex);
418
419     style.width          = fontDescriptionRun.width;
420     style.isWidthDefined = true;
421   }
422
423   // Set the font's slant if it's overriden.
424   if(slantOverriden)
425   {
426     const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + slantIndex);
427
428     style.slant          = fontDescriptionRun.slant;
429     style.isSlantDefined = true;
430   }
431
432   // Set the font's size if it's overriden.
433   if(sizeOverriden)
434   {
435     const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + sizeIndex);
436
437     style.size          = static_cast<float>(fontDescriptionRun.size) / 64.f;
438     style.isSizeDefined = true;
439   }
440 }
441
442 void LogicalModel::ClearFontDescriptionRuns()
443 {
444   FreeFontFamilyNames(mFontDescriptionRuns);
445 }
446
447 void LogicalModel::CreateParagraphInfo(CharacterIndex startIndex,
448                                        Length         numberOfCharacters)
449 {
450   const Length totalNumberOfCharacters = mLineBreakInfo.Count();
451
452   // Count the number of LINE_MUST_BREAK to reserve some space for the vector of paragraph's info.
453   Vector<CharacterIndex> paragraphs;
454   paragraphs.Reserve(numberOfCharacters);
455   const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer       = mLineBreakInfo.Begin();
456   const CharacterIndex                  lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
457   for(Length index = startIndex; index < lastCharacterIndexPlusOne; ++index)
458   {
459     if(TextAbstraction::LINE_MUST_BREAK == *(lineBreakInfoBuffer + index))
460     {
461       paragraphs.PushBack(index);
462     }
463   }
464
465   // Whether the current paragraphs are updated or set from scratch.
466   const bool updateCurrentParagraphs = numberOfCharacters < totalNumberOfCharacters;
467
468   // Reserve space for current paragraphs plus new ones.
469   const Length numberOfNewParagraphs   = paragraphs.Count();
470   const Length totalNumberOfParagraphs = mParagraphInfo.Count() + numberOfNewParagraphs;
471   mParagraphInfo.Resize(totalNumberOfParagraphs);
472
473   ParagraphRun*        paragraphInfoBuffer = NULL;
474   Vector<ParagraphRun> newParagraphs;
475
476   if(updateCurrentParagraphs)
477   {
478     newParagraphs.Resize(numberOfNewParagraphs);
479     paragraphInfoBuffer = newParagraphs.Begin();
480   }
481   else
482   {
483     paragraphInfoBuffer = mParagraphInfo.Begin();
484   }
485
486   // Find where to insert the new paragraphs.
487   ParagraphRunIndex paragraphIndex = 0u;
488   CharacterIndex    firstIndex     = startIndex;
489
490   if(updateCurrentParagraphs)
491   {
492     for(Vector<ParagraphRun>::ConstIterator it    = mParagraphInfo.Begin(),
493                                             endIt = mParagraphInfo.Begin() + totalNumberOfParagraphs - numberOfNewParagraphs;
494         it != endIt;
495         ++it)
496     {
497       const ParagraphRun& paragraph(*it);
498
499       if(startIndex < paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters)
500       {
501         firstIndex = paragraph.characterRun.characterIndex;
502         break;
503       }
504
505       ++paragraphIndex;
506     }
507   }
508
509   // Create the paragraph info.
510   ParagraphRunIndex newParagraphIndex = 0u;
511   for(Vector<CharacterIndex>::ConstIterator it    = paragraphs.Begin(),
512                                             endIt = paragraphs.End();
513       it != endIt;
514       ++it, ++newParagraphIndex)
515   {
516     const CharacterIndex index = *it;
517
518     ParagraphRun& paragraph                   = *(paragraphInfoBuffer + newParagraphIndex);
519     paragraph.characterRun.characterIndex     = firstIndex;
520     paragraph.characterRun.numberOfCharacters = 1u + index - firstIndex;
521
522     firstIndex += paragraph.characterRun.numberOfCharacters;
523   }
524
525   // Insert the new paragraphs.
526   if(updateCurrentParagraphs)
527   {
528     mParagraphInfo.Insert(mParagraphInfo.Begin() + paragraphIndex,
529                           newParagraphs.Begin(),
530                           newParagraphs.End());
531
532     mParagraphInfo.Resize(totalNumberOfParagraphs);
533
534     // Update the next paragraph indices.
535     for(Vector<ParagraphRun>::Iterator it    = mParagraphInfo.Begin() + paragraphIndex + newParagraphs.Count(),
536                                        endIt = mParagraphInfo.End();
537         it != endIt;
538         ++it)
539     {
540       ParagraphRun& paragraph(*it);
541
542       paragraph.characterRun.characterIndex += numberOfCharacters;
543     }
544   }
545 }
546
547 void LogicalModel::FindParagraphs(CharacterIndex             index,
548                                   Length                     numberOfCharacters,
549                                   Vector<ParagraphRunIndex>& paragraphs)
550 {
551   // Reserve som space for the paragraph indices.
552   paragraphs.Reserve(mParagraphInfo.Count());
553
554   // Traverse the paragraphs to find which ones contain the given characters.
555   ParagraphRunIndex paragraphIndex = 0u;
556   for(Vector<ParagraphRun>::ConstIterator it    = mParagraphInfo.Begin(),
557                                           endIt = mParagraphInfo.End();
558       it != endIt;
559       ++it, ++paragraphIndex)
560   {
561     const ParagraphRun& paragraph(*it);
562
563     if((paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters > index) &&
564        (paragraph.characterRun.characterIndex < index + numberOfCharacters))
565     {
566       paragraphs.PushBack(paragraphIndex);
567     }
568   }
569 }
570
571 void LogicalModel::ClearEmbeddedImages()
572 {
573   FreeEmbeddedItems(mEmbeddedItems);
574 }
575
576 LogicalModel::~LogicalModel()
577 {
578   ClearFontDescriptionRuns();
579   ClearEmbeddedImages();
580 }
581
582 LogicalModel::LogicalModel()
583 : mBidirectionalLineIndex(0u)
584 {
585 }
586
587 } // namespace Text
588
589 } // namespace Toolkit
590
591 } // namespace Dali