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