8af3e91d610e6a8e52022da88807b234f761c8cf
[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( const BidirectionalLineInfoRun* const bidirectionalInfo,
82                                           Length numberOfRuns,
83                                           CharacterIndex startIndex,
84                                           Length numberOfCharacters )
85 {
86   mVisualToLogicalMap.Resize( numberOfCharacters );
87   mLogicalToVisualMap.Resize( numberOfCharacters );
88
89   const Length numberOfCharactersPlus = numberOfCharacters + 1u;
90   mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
91
92   CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
93   CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
94
95   CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
96
97   CharacterIndex lastIndex = startIndex;
98   for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
99   {
100     const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
101
102     if( bidiLineInfo.characterRun.characterIndex + bidiLineInfo.characterRun.numberOfCharacters <= startIndex )
103     {
104       // Skip this paragraph. It has been already processed.
105       continue;
106     }
107
108     if( lastIndex < bidiLineInfo.characterRun.characterIndex )
109     {
110       // Fill with the identity.
111       for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
112       {
113         *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
114       }
115     }
116
117     // Fill the conversion table of the run.
118     for( CharacterIndex index = 0u;
119          index < bidiLineInfo.characterRun.numberOfCharacters;
120          ++index, ++lastIndex )
121     {
122       *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
123     }
124   }
125
126   // Complete with the identity if there are some left to right characters after the last right to left.
127   for( ; lastIndex < numberOfCharacters; ++lastIndex )
128   {
129     *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
130   }
131
132   // Sets the logical to visual conversion map.
133   for( CharacterIndex index = startIndex; index < numberOfCharacters; ++index )
134   {
135     *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
136   }
137
138   // Sets the visual to logical conversion map for cursor positions.
139
140   const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
141   BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
142   BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
143
144   const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
145
146   Length bidirectionalParagraphIndex = 0u;
147   bool isRightToLeftParagraph = false;
148   for( CharacterIndex index = startIndex; index < numberOfCharactersPlus; ++index )
149   {
150     if( bidirectionalParagraph &&
151         ( bidirectionalParagraph->characterRun.characterIndex == index ) )
152     {
153       isRightToLeftParagraph = *( modelCharacterDirections + index );
154     }
155
156     if( 0u == index )
157     {
158       if( isRightToLeftParagraph )
159       {
160         *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
161       }
162       else // else logical position is zero.
163       {
164         *( modelVisualToLogicalCursorMap + index ) = 0u;
165       }
166     }
167     else if( numberOfCharacters == index )
168     {
169       if( isRightToLeftParagraph )
170       {
171         *( modelVisualToLogicalCursorMap + index ) = 0u;
172       }
173       else // else logical position is the number of characters.
174       {
175         *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
176       }
177     }
178     else
179     {
180       // Get the character indexed by  index - 1 and index
181       // and calculate the logical position according the directions of
182       // both characters and the direction of the paragraph.
183
184       const CharacterIndex previousIndex = index - 1u;
185       const CharacterIndex logicalPosition0 = *( modelVisualToLogicalMapBuffer + previousIndex );
186       const CharacterIndex logicalPosition1 = *( modelVisualToLogicalMapBuffer + index );
187
188       const CharacterDirection direction0 = *( modelCharacterDirections + logicalPosition0 );
189       const CharacterDirection direction1 = *( modelCharacterDirections + logicalPosition1 );
190
191       if( direction0 == direction1 )
192       {
193         // Both glyphs have the same direction.
194         if( direction0 )
195         {
196           *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
197         }
198         else
199         {
200           *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
201         }
202       }
203       else
204       {
205         if( isRightToLeftParagraph )
206         {
207           if( direction1 )
208           {
209             *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
210           }
211           else
212           {
213             *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
214           }
215         }
216         else
217         {
218           if( direction0 )
219           {
220             *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
221           }
222           else
223           {
224             *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
225           }
226         }
227       }
228     }
229
230     if( bidirectionalParagraph &&
231         ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
232     {
233       isRightToLeftParagraph = false;
234       ++bidirectionalParagraphIndex;
235       if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
236       {
237         bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
238       }
239       else
240       {
241         bidirectionalParagraph = NULL;
242       }
243     }
244   }
245 }
246
247 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
248 {
249   if( 0u == mVisualToLogicalMap.Count() )
250   {
251     // If there is no visual to logical info is because the whole text is left to right.
252     // Return the identity.
253     return visualCharacterIndex;
254   }
255
256   return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
257 }
258
259 void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters )
260 {
261   const Length totalNumberOfCharacters = mText.Count();
262
263   // Process the color runs.
264   Vector<ColorRun> removedColorRuns;
265   UpdateCharacterRuns<ColorRun>( index,
266                                  numberOfCharacters,
267                                  totalNumberOfCharacters,
268                                  mColorRuns,
269                                  removedColorRuns );
270
271   // Process the font description runs.
272   Vector<FontDescriptionRun> removedFontDescriptionRuns;
273   UpdateCharacterRuns<FontDescriptionRun>( index,
274                                            numberOfCharacters,
275                                            totalNumberOfCharacters,
276                                            mFontDescriptionRuns,
277                                            removedFontDescriptionRuns );
278
279   // Free memory allocated for the font family name.
280   FreeFontFamilyNames( removedFontDescriptionRuns );
281 }
282
283 void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
284 {
285   unsigned int runIndex = 0u;
286
287   // Set the text color.
288   bool colorOverriden = false;
289   unsigned int colorIndex = 0u;
290   const ColorRun* const colorRunsBuffer = mColorRuns.Begin();
291   for( Vector<ColorRun>::ConstIterator it = colorRunsBuffer,
292          endIt = mColorRuns.End();
293        it != endIt;
294        ++it, ++runIndex )
295   {
296     const ColorRun& colorRun = *it;
297
298     if( ( colorRun.characterRun.characterIndex <= index ) &&
299         ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) )
300     {
301       colorIndex = runIndex;
302       colorOverriden = true;
303     }
304   }
305
306   // Set the text's color if it's overriden.
307   if( colorOverriden )
308   {
309     style.textColor = ( *( colorRunsBuffer + colorIndex ) ).color;
310   }
311
312   // Reset the run index.
313   runIndex = 0u;
314
315   // Set the font's parameters.
316   bool nameOverriden = false;
317   bool weightOverriden = false;
318   bool widthOverriden = false;
319   bool slantOverriden = false;
320   bool sizeOverriden = false;
321   unsigned int nameIndex = 0u;
322   unsigned int weightIndex = 0u;
323   unsigned int widthIndex = 0u;
324   unsigned int slantIndex = 0u;
325   unsigned int sizeIndex = 0u;
326   const FontDescriptionRun* const fontDescriptionRunsBuffer = mFontDescriptionRuns.Begin();
327   for( Vector<FontDescriptionRun>::ConstIterator it = fontDescriptionRunsBuffer,
328          endIt = mFontDescriptionRuns.End();
329        it != endIt;
330        ++it, ++runIndex )
331   {
332     const FontDescriptionRun& fontDescriptionRun = *it;
333
334     if( ( fontDescriptionRun.characterRun.characterIndex <= index ) &&
335         ( index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters ) )
336     {
337       if( fontDescriptionRun.familyDefined )
338       {
339         nameIndex = runIndex;
340         nameOverriden = true;
341       }
342
343       if( fontDescriptionRun.weightDefined )
344       {
345         weightIndex = runIndex;
346         weightOverriden = true;
347       }
348
349       if( fontDescriptionRun.widthDefined )
350       {
351         widthIndex = runIndex;
352         widthOverriden = true;
353       }
354
355       if( fontDescriptionRun.slantDefined )
356       {
357         slantIndex = runIndex;
358         slantOverriden = true;
359       }
360
361       if( fontDescriptionRun.sizeDefined )
362       {
363         sizeIndex = runIndex;
364         sizeOverriden = true;
365       }
366     }
367   }
368
369   // Set the font's family name if it's overriden.
370   if( nameOverriden )
371   {
372     const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + nameIndex );
373
374     style.familyName = std::string( fontDescriptionRun.familyName, fontDescriptionRun.familyLength );
375     style.familyDefined = true;
376   }
377
378   // Set the font's weight if it's overriden.
379   if( weightOverriden )
380   {
381     const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + weightIndex );
382
383     style.weight = fontDescriptionRun.weight;
384     style.weightDefined = true;
385   }
386
387   // Set the font's width if it's overriden.
388   if( widthOverriden )
389   {
390     const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + widthIndex );
391
392     style.width = fontDescriptionRun.width;
393     style.widthDefined = true;
394   }
395
396   // Set the font's slant if it's overriden.
397   if( slantOverriden )
398   {
399     const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + slantIndex );
400
401     style.slant = fontDescriptionRun.slant;
402     style.slantDefined = true;
403   }
404
405   // Set the font's size if it's overriden.
406   if( sizeOverriden )
407   {
408     const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + sizeIndex );
409
410     style.size = static_cast<float>( fontDescriptionRun.size ) / 64.f;
411     style.sizeDefined = true;
412   }
413
414   // Reset the run index.
415   runIndex = 0u;
416 }
417
418 void LogicalModel::ClearFontDescriptionRuns()
419 {
420   FreeFontFamilyNames( mFontDescriptionRuns );
421 }
422
423 LogicalModel::~LogicalModel()
424 {
425   ClearFontDescriptionRuns();
426 }
427
428 LogicalModel::LogicalModel()
429 {
430 }
431
432 } // namespace Text
433
434 } // namespace Toolkit
435
436 } // namespace Dali