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