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