Merge "Retrieves character's directions." into new_text
[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 // EXTERNAL INCLUDES
22 #include <memory.h>
23
24 namespace Dali
25 {
26
27 namespace Toolkit
28 {
29
30 namespace Text
31 {
32
33 LogicalModelPtr LogicalModel::New()
34 {
35   return LogicalModelPtr( new LogicalModel() );
36 }
37
38 void LogicalModel::SetText( const Character* const text,
39                             Length numberOfCharacters )
40 {
41   if( 0u == numberOfCharacters )
42   {
43     mText.Clear();
44   }
45   else
46   {
47     mText.Resize( numberOfCharacters );
48     memcpy( mText.Begin(), text, numberOfCharacters * sizeof( Character ) );
49   }
50 }
51
52 Length LogicalModel::GetNumberOfCharacters() const
53 {
54   return mText.Count();
55 }
56
57 void LogicalModel::GetText( Character* text,
58                             CharacterIndex characterIndex,
59                             Length numberOfCharacters ) const
60 {
61   memcpy( text, mText.Begin() + characterIndex, numberOfCharacters * sizeof( Character ) );
62 }
63
64 Character LogicalModel::GetCharacter( CharacterIndex characterIndex ) const
65 {
66   return mText[characterIndex];
67 }
68
69 void LogicalModel::ReplaceText( CharacterIndex characterIndex,
70                                 Length numberOfCharactersToRemove,
71                                 const Character* const text,
72                                 Length numberOfCharactersToInsert )
73 {
74 }
75
76 void LogicalModel::SetScripts( const ScriptRun* const scripts,
77                                Length numberOfRuns )
78 {
79   if( 0u == numberOfRuns )
80   {
81     mScriptRuns.Clear();
82   }
83   else
84   {
85     mScriptRuns.Resize( numberOfRuns );
86     memcpy( mScriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) );
87   }
88 }
89
90 void LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex,
91                                           Length numberOfCharacters,
92                                           ScriptRunIndex& firstScriptRun,
93                                           Length& numberOfScriptRuns ) const
94 {
95   // Initialize the number of scripts and the index to the first script.
96   firstScriptRun = 0u;
97   numberOfScriptRuns = 0;
98   bool firstScriptFound = false;
99
100   const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
101
102   // Traverse the scripts and count those scripts within the range of characters.
103   for( Vector<ScriptRun>::ConstIterator it = mScriptRuns.Begin(),
104          endIt = mScriptRuns.End();
105        it != endIt;
106        ++it )
107   {
108     const ScriptRun& script = *it;
109
110     if( ( script.characterRun.characterIndex + script.characterRun.numberOfCharacters > characterIndex ) &&
111         ( lastCharacterIndex > script.characterRun.characterIndex ) )
112     {
113       firstScriptFound = true;
114       ++numberOfScriptRuns;
115     }
116     else if( lastCharacterIndex <= script.characterRun.characterIndex )
117     {
118       // nothing else to do.
119       break;
120     }
121
122     if( !firstScriptFound )
123     {
124       ++firstScriptRun;
125     }
126   }
127 }
128
129 void LogicalModel::GetScriptRuns( ScriptRun* scriptRuns,
130                                   CharacterIndex characterIndex,
131                                   Length numberOfCharacters ) const
132 {
133   ScriptRunIndex firstScriptRun = 0u;
134   Length numberOfScriptRuns = 0u;
135
136   GetNumberOfScriptRuns( characterIndex,
137                          numberOfCharacters,
138                          firstScriptRun,
139                          numberOfScriptRuns );
140
141   memcpy( scriptRuns, mScriptRuns.Begin() + firstScriptRun, numberOfScriptRuns * sizeof( ScriptRun ) );
142 }
143
144 Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
145 {
146   // If this operation is too slow, consider a binary search.
147
148   for( Length index = 0u, length = mScriptRuns.Count(); index < length; ++index )
149   {
150     const ScriptRun* const scriptRun = mScriptRuns.Begin() + index;
151
152     if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
153         ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
154     {
155       return scriptRun->script;
156     }
157   }
158
159   return TextAbstraction::UNKNOWN;
160 }
161
162 void LogicalModel::ReplaceScripts( CharacterIndex characterIndex,
163                                    Length numberOfCharactersToRemove,
164                                    const ScriptRun* const scriptRuns,
165                                    Length numberOfCharactersToInsert )
166 {
167 }
168
169 void LogicalModel::SetFonts( const FontRun* const fonts,
170                              Length numberOfRuns )
171 {
172   if( 0u == numberOfRuns )
173   {
174     mFontRuns.Clear();
175   }
176   else
177   {
178     mFontRuns.Resize( numberOfRuns );
179     memcpy( mFontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) );
180   }
181 }
182
183 void LogicalModel::GetNumberOfFontRuns( CharacterIndex characterIndex,
184                                         Length numberOfCharacters,
185                                         FontRunIndex& firstFontRun,
186                                         Length& numberOfFontRuns ) const
187 {
188   // Initialize the number of fonts and the index to the first font.
189   firstFontRun = 0u;
190   numberOfFontRuns = 0;
191   bool firstFontFound = false;
192
193   const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
194
195   // Traverse the fonts and count those fonts within the range of characters.
196   for( Vector<FontRun>::ConstIterator it = mFontRuns.Begin(),
197          endIt = mFontRuns.End();
198        it != endIt;
199        ++it )
200   {
201     const FontRun& font = *it;
202
203     if( ( font.characterRun.characterIndex + font.characterRun.numberOfCharacters > characterIndex ) &&
204         ( characterIndex + numberOfCharacters > font.characterRun.characterIndex ) )
205     {
206       firstFontFound = true;
207       ++numberOfFontRuns;
208     }
209     else if( lastCharacterIndex <= font.characterRun.characterIndex )
210     {
211       // nothing else to do.
212       break;
213     }
214
215     if( !firstFontFound )
216     {
217       ++firstFontRun;
218     }
219   }
220 }
221
222 void LogicalModel::GetFontRuns( FontRun* fontRuns,
223                                 CharacterIndex characterIndex,
224                                 Length numberOfCharacters ) const
225 {
226   FontRunIndex firstFontRun = 0u;
227   Length numberOfFontRuns = 0u;
228
229   GetNumberOfFontRuns( characterIndex,
230                        numberOfCharacters,
231                        firstFontRun,
232                        numberOfFontRuns );
233
234   memcpy( fontRuns, mFontRuns.Begin() + firstFontRun, numberOfFontRuns * sizeof( FontRun ) );
235 }
236
237 FontId LogicalModel::GetFont( CharacterIndex characterIndex ) const
238 {
239   for( Length index = 0u, length = mFontRuns.Count(); index < length; ++index )
240   {
241     const FontRun* const fontRun = mFontRuns.Begin() + index;
242
243     if( ( fontRun->characterRun.characterIndex <= characterIndex ) &&
244         ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) )
245     {
246       return fontRun->fontId;
247     }
248   }
249
250   return 0u;
251 }
252
253 void LogicalModel::ReplaceFonts( CharacterIndex characterIndex,
254                                  Length numberOfCharactersToRemove,
255                                  const FontRun* const fontRuns,
256                                  Length numberOfCharactersToInsert )
257 {
258 }
259
260 void LogicalModel::SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
261                                      Length length )
262 {
263   if( 0u == length )
264   {
265     mLineBreakInfo.Clear();
266   }
267   else
268   {
269     mLineBreakInfo.Resize( length );
270     memcpy( mLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) );
271   }
272 }
273
274 void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
275                                      CharacterIndex characterIndex,
276                                      Length numberOfItems ) const
277 {
278   memcpy( lineBreakInfo, mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) );
279 }
280
281 LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const
282 {
283   return *( mLineBreakInfo.Begin() + characterIndex );
284 }
285
286 void LogicalModel::ReplaceLineBreakInfo( CharacterIndex characterIndex,
287                                          Length numberOfItemsToRemove,
288                                          const LineBreakInfo* const lineBreakInfo,
289                                          Length numberOfItemsToInsert )
290 {
291 }
292
293 void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
294                                      Length length )
295 {
296   if( 0u == length )
297   {
298     mWordBreakInfo.Clear();
299   }
300   else
301   {
302     mWordBreakInfo.Resize( length );
303     memcpy( mWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) );
304   }
305 }
306
307 void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
308                                      CharacterIndex characterIndex,
309                                      Length numberOfItems ) const
310 {
311   memcpy( wordBreakInfo, mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) );
312 }
313
314 WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const
315 {
316   return *( mWordBreakInfo.Begin() + characterIndex );
317 }
318
319 void LogicalModel::ReplaceWordBreakInfo( CharacterIndex characterIndex,
320                                          Length numberOfItemsToRemove,
321                                          const WordBreakInfo* const wordBreakInfo,
322                                          Length numberOfItemsToInsert )
323 {
324 }
325
326 void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
327                                          Length numberOfRuns )
328 {
329   if( 0u == numberOfRuns )
330   {
331     mBidirectionalParagraphInfo.Clear();
332   }
333   else
334   {
335     mBidirectionalParagraphInfo.Resize( numberOfRuns );
336     memcpy( mBidirectionalParagraphInfo.Begin(), bidirectionalInfo, numberOfRuns * sizeof( BidirectionalParagraphInfoRun ) );
337   }
338 }
339
340 void LogicalModel::GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
341                                                      Length numberOfCharacters,
342                                                      BidirectionalRunIndex& firstBidirectionalRun,
343                                                      Length& numberOfFontRuns  ) const
344 {
345   // Initialize the number of bidi paragraphs and the index to the first paragraph.
346   firstBidirectionalRun = 0u;
347   numberOfFontRuns = 0;
348   bool firstParagraphFound = false;
349
350   // Traverse the bidirectional paragraph info and count those bidi paragraphs within the range of characters.
351   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = mBidirectionalParagraphInfo.Begin(),
352          endIt = mBidirectionalParagraphInfo.End();
353        it != endIt;
354        ++it )
355   {
356     const BidirectionalParagraphInfoRun& bidi = *it;
357
358     if( ( bidi.characterRun.characterIndex + bidi.characterRun.numberOfCharacters > characterIndex ) &&
359         ( characterIndex + numberOfCharacters > bidi.characterRun.characterIndex ) )
360     {
361       firstParagraphFound = true;
362       ++numberOfFontRuns;
363     }
364
365     if( !firstParagraphFound )
366     {
367       ++firstBidirectionalRun;
368     }
369   }
370 }
371
372 void LogicalModel::GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo,
373                                          CharacterIndex characterIndex,
374                                          Length numberOfCharacters ) const
375 {
376   BidirectionalRunIndex firstBidirectionalRun = 0u;
377   Length numberOfFontRuns = 0u;
378
379   GetNumberOfBidirectionalInfoRuns( characterIndex,
380                                     numberOfCharacters,
381                                     firstBidirectionalRun,
382                                     numberOfFontRuns );
383
384   memcpy( bidirectionalInfo, mBidirectionalParagraphInfo.Begin() + firstBidirectionalRun, numberOfFontRuns * sizeof( BidirectionalParagraphInfoRun ) );
385 }
386
387 void ReplaceBidirectionalInfo( CharacterIndex characterIndex,
388                                Length numberOfCharactersToRemove,
389                                const BidirectionalParagraphInfoRun* const bidirectionalInfo,
390                                Length numberOfCharactersToInsert )
391 {
392 }
393
394 void LogicalModel::SetCharacterDirections( const CharacterDirection* const directions,
395                                            Length numberOfCharacters )
396 {
397   if( 0u == numberOfCharacters )
398   {
399     mCharacterDirections.Clear();
400   }
401   else
402   {
403     mCharacterDirections.Resize( numberOfCharacters );
404     memcpy( mCharacterDirections.Begin(), directions, numberOfCharacters * sizeof( CharacterDirection ) );
405   }
406 }
407
408 void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
409                                            CharacterIndex characterIndex,
410                                            Length numberOfCharacters ) const
411 {
412   if( 0u == mCharacterDirections.Count() )
413   {
414     // Nothing to retrieve if the model has no right to left characters.
415     return;
416   }
417
418   memcpy( directions, mCharacterDirections.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterDirection ) );
419 }
420
421 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
422 {
423   if( characterIndex >= mCharacterDirections.Count() )
424   {
425     // The model has no right to left characters, so the vector of directions is void.
426     return false;
427   }
428
429   return *( mCharacterDirections.Begin() + characterIndex );
430 }
431
432 void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
433                                           Length numberOfRuns )
434 {
435   if( 0u == numberOfRuns )
436   {
437     mVisualToLogicalMap.Clear();
438     mLogicalToVisualMap.Clear();
439   }
440   else
441   {
442     const Length numberOfCharacters = mText.Count();
443     mVisualToLogicalMap.Resize( numberOfCharacters );
444     mLogicalToVisualMap.Resize( numberOfCharacters );
445
446     CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
447     CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
448
449     CharacterIndex lastIndex = 0u;
450     for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
451     {
452       const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
453
454       if( lastIndex < bidiLineInfo.characterRun.characterIndex )
455       {
456         // Fill with the identity.
457         for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
458         {
459           *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
460         }
461       }
462
463       // Fill the conversion table of the run.
464       for( CharacterIndex index = 0u;
465            index < bidiLineInfo.characterRun.numberOfCharacters;
466            ++index, ++lastIndex )
467       {
468         *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
469       }
470     }
471
472     // Complete with the identity if there are some left to right characters after the last right to left.
473     for( ; lastIndex < numberOfCharacters; ++lastIndex )
474     {
475       *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
476     }
477
478     // Sets the logical to visual conversion map.
479     for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
480     {
481       *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
482     }
483   }
484 }
485
486 void LogicalModel::ReplaceVisualToLogicalMap( CharacterIndex characterIndex,
487                                               Length numberOfCharactersToRemove,
488                                               const BidirectionalLineInfoRun* const bidirectionalInfo,
489                                               Length numberOfCharactersToInsert )
490 {
491 }
492
493 CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
494 {
495   if( 0u == mLogicalToVisualMap.Count() )
496   {
497     // If there is no logical to visual info is because the whole text is left to right.
498     // Return the identity.
499     return logicalCharacterIndex;
500   }
501
502   return *( mLogicalToVisualMap.Begin() + logicalCharacterIndex );
503 }
504
505 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
506 {
507   if( 0u == mVisualToLogicalMap.Count() )
508   {
509     // If there is no visual to logical info is because the whole text is left to right.
510     // Return the identity.
511     return visualCharacterIndex;
512   }
513
514   return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
515 }
516
517 void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
518                                           CharacterIndex characterIndex,
519                                           Length numberOfCharacters ) const
520 {
521   memcpy( logicalToVisualMap, mLogicalToVisualMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
522 }
523
524 void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
525                                           CharacterIndex characterIndex,
526                                           Length numberOfCharacters ) const
527 {
528   memcpy( visualToLogicalMap, mVisualToLogicalMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
529 }
530
531 LogicalModel::~LogicalModel()
532 {
533 }
534
535 LogicalModel::LogicalModel()
536 {
537 }
538
539 } // namespace Text
540
541 } // namespace Toolkit
542
543 } // namespace Dali