807f7fb65df7ee43c1452110275a0004790de39c
[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::GetCharacterDirections( CharacterDirection* directions,
395                                            CharacterIndex characterIndex,
396                                            Length numberOfCharacters ) const
397 {
398 }
399
400 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
401 {
402   return false;
403 }
404
405 void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
406                                           Length numberOfRuns )
407 {
408   if( 0u == numberOfRuns )
409   {
410     mVisualToLogicalMap.Clear();
411     mLogicalToVisualMap.Clear();
412   }
413   else
414   {
415     const Length numberOfCharacters = mText.Count();
416     mVisualToLogicalMap.Resize( numberOfCharacters );
417     mLogicalToVisualMap.Resize( numberOfCharacters );
418
419     CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
420     CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
421
422     CharacterIndex lastIndex = 0u;
423     for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
424     {
425       const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
426
427       if( lastIndex < bidiLineInfo.characterRun.characterIndex )
428       {
429         // Fill with the identity.
430         for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
431         {
432           *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
433         }
434       }
435
436       // Fill the conversion table of the run.
437       for( CharacterIndex index = 0u;
438            index < bidiLineInfo.characterRun.numberOfCharacters;
439            ++index, ++lastIndex )
440       {
441         *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
442       }
443     }
444
445     // Complete with the identity if there are some left to right characters after the last right to left.
446     for( ; lastIndex < numberOfCharacters; ++lastIndex )
447     {
448       *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
449     }
450
451     // Sets the logical to visual conversion map.
452     for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
453     {
454       *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
455     }
456   }
457 }
458
459 void LogicalModel::ReplaceVisualToLogicalMap( CharacterIndex characterIndex,
460                                               Length numberOfCharactersToRemove,
461                                               const BidirectionalLineInfoRun* const bidirectionalInfo,
462                                               Length numberOfCharactersToInsert )
463 {
464 }
465
466 CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
467 {
468   if( 0u == mLogicalToVisualMap.Count() )
469   {
470     // If there is no logical to visual info is because the whole text is left to right.
471     // Return the identity.
472     return logicalCharacterIndex;
473   }
474
475   return *( mLogicalToVisualMap.Begin() + logicalCharacterIndex );
476 }
477
478 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
479 {
480   if( 0u == mVisualToLogicalMap.Count() )
481   {
482     // If there is no visual to logical info is because the whole text is left to right.
483     // Return the identity.
484     return visualCharacterIndex;
485   }
486
487   return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
488 }
489
490 void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
491                                           CharacterIndex characterIndex,
492                                           Length numberOfCharacters ) const
493 {
494   memcpy( logicalToVisualMap, mLogicalToVisualMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
495 }
496
497 void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
498                                           CharacterIndex characterIndex,
499                                           Length numberOfCharacters ) const
500 {
501   memcpy( visualToLogicalMap, mVisualToLogicalMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
502 }
503
504 LogicalModel::~LogicalModel()
505 {
506 }
507
508 LogicalModel::LogicalModel()
509 {
510 }
511
512 } // namespace Text
513
514 } // namespace Toolkit
515
516 } // namespace Dali