Logical model.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / logical-model.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.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
23 #include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
24 #include <dali-toolkit/internal/text/font-run.h>
25 #include <dali-toolkit/internal/text/script-run.h>
26
27 // EXTERNAL INCLUDES
28 #include <memory.h>
29
30 namespace Dali
31 {
32
33 namespace Toolkit
34 {
35
36 namespace Text
37 {
38 /**
39  * @brief caches some temporary values of the GetNumberOfScriptRuns( characterIndex, numberOfCharacters )
40  * operation and the GetNumberOfFontRuns( characterIndex, numberOfCharacters ) as they are going to be
41  * used in the GetScriptRuns() and the GetFontRuns() calls.
42  */
43 struct GetRunCache
44 {
45   CharacterIndex characterIndex;     ///< The character index.
46   Length         numberOfCharacters; ///< The number of characters.
47   Length         firstRun;           ///< Index to the first run.
48   Length         numberOfRuns;       ///< The number of runs.
49 };
50
51 struct LogicalModel::Impl
52 {
53   Vector<Character>     mText;
54   Vector<ScriptRun>     mScriptRuns;
55   Vector<FontRun>       mFontRuns;
56   Vector<LineBreakInfo> mLineBreakInfo;
57   Vector<WordBreakInfo> mWordBreakInfo;
58
59   GetRunCache           mGetScriptCache; ///< Caches the GetNumberOfScriptRuns( characterIndex, numberOfCharacters ) operation.
60   GetRunCache           mGetFontCache;   ///< Caches the GetNumberOfFontRuns( characterIndex, numberOfCharacters ) operation.
61 };
62
63 LogicalModelPtr LogicalModel::New()
64 {
65   return LogicalModelPtr( new LogicalModel() );
66 }
67
68 void LogicalModel::SetText( const Character* const text,
69                             Length numberOfCharacters )
70 {
71   Vector<Character>& modelText = mImpl->mText;
72
73   if( 0u == numberOfCharacters )
74   {
75     modelText.Clear();
76   }
77   else
78   {
79     modelText.Resize( numberOfCharacters );
80     memcpy( modelText.Begin(), text, numberOfCharacters * sizeof( Character ) );
81   }
82 }
83
84 Length LogicalModel::GetNumberOfCharacters() const
85 {
86   return mImpl->mText.Count();
87 }
88
89 void LogicalModel::GetText( CharacterIndex characterIndex,
90                             Character* text,
91                             Length numberOfCharacters ) const
92 {
93   Vector<Character>& modelText = mImpl->mText;
94   memcpy( text, modelText.Begin() + characterIndex, numberOfCharacters * sizeof( Character ) );
95 }
96
97 Character LogicalModel::GetCharacter( CharacterIndex characterIndex ) const
98 {
99   return mImpl->mText[characterIndex];
100 }
101
102 void LogicalModel::SetScripts( const ScriptRun* const scripts,
103                                Length numberOfRuns )
104 {
105   Vector<ScriptRun>& scriptRuns = mImpl->mScriptRuns;
106
107   if( 0u == numberOfRuns )
108   {
109     scriptRuns.Clear();
110   }
111   else
112   {
113     scriptRuns.Resize( numberOfRuns );
114     memcpy( scriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) );
115   }
116
117   mImpl->mGetScriptCache.characterIndex = 0u;
118   mImpl->mGetScriptCache.numberOfCharacters = 0u;
119   mImpl->mGetScriptCache.firstRun = 0u;
120   mImpl->mGetScriptCache.numberOfRuns = 0u;
121 }
122
123 Length LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex,
124                                             Length numberOfCharacters ) const
125 {
126   GetRunCache& scriptCache = mImpl->mGetScriptCache;
127
128   // Set the character index and the number of characters into the cache.
129   scriptCache.characterIndex = characterIndex;
130   scriptCache.numberOfCharacters = numberOfCharacters;
131
132   if( ( 0u == characterIndex ) &&
133       ( mImpl->mText.Count() == numberOfCharacters ) )
134   {
135     scriptCache.firstRun = 0u;
136     scriptCache.numberOfRuns = mImpl->mScriptRuns.Count();
137     return scriptCache.numberOfRuns;
138   }
139
140   // Initialize the number of scripts and the index to the first script.
141   scriptCache.firstRun = 0u;
142   scriptCache.numberOfRuns = 0;
143   bool firstScriptFound = false;
144
145   const Vector<ScriptRun>& modelScripts = mImpl->mScriptRuns;
146   const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
147
148   // Traverse the scripts and count those scripts within the range of characters.
149   for( Vector<ScriptRun>::ConstIterator it = modelScripts.Begin(),
150          endIt = modelScripts.End();
151        it != endIt;
152        ++it )
153   {
154     const ScriptRun& script = *it;
155
156     if( ( script.characterRun.characterIndex + script.characterRun.numberOfCharacters > characterIndex ) &&
157         ( lastCharacterIndex > script.characterRun.characterIndex ) )
158     {
159       firstScriptFound = true;
160       ++scriptCache.numberOfRuns;
161     }
162     else if( lastCharacterIndex <= script.characterRun.characterIndex )
163     {
164       // nothing else to do.
165       break;
166     }
167
168     if( !firstScriptFound )
169     {
170       ++scriptCache.firstRun;
171     }
172   }
173
174   return scriptCache.numberOfRuns;
175 }
176
177 void LogicalModel::GetScriptRuns( ScriptRun* scriptRuns,
178                                   CharacterIndex characterIndex,
179                                   Length numberOfCharacters ) const
180 {
181   const Vector<ScriptRun>& modelScripts = mImpl->mScriptRuns;
182   GetRunCache& scriptCache = mImpl->mGetScriptCache;
183
184   if( ( characterIndex != scriptCache.characterIndex ) ||
185       ( numberOfCharacters != scriptCache.numberOfCharacters ) )
186   {
187     GetNumberOfScriptRuns( characterIndex,
188                            numberOfCharacters );
189   }
190
191   memcpy( scriptRuns, modelScripts.Begin() + scriptCache.firstRun, scriptCache.numberOfRuns * sizeof( ScriptRun ) );
192 }
193
194 Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
195 {
196   // If this operation is too slow, consider a binary search.
197
198   for( Length index = 0u, length = mImpl->mScriptRuns.Count(); index < length; ++index )
199   {
200     const ScriptRun* const scriptRun = mImpl->mScriptRuns.Begin() + index;
201
202     if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
203         ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
204     {
205       return scriptRun->script;
206     }
207   }
208
209   return TextAbstraction::UNKNOWN;
210 }
211
212 void LogicalModel::SetFonts( const FontRun* const fonts,
213                              Length numberOfRuns )
214 {
215   Vector<FontRun>& fontRuns = mImpl->mFontRuns;
216
217   if( 0u == numberOfRuns )
218   {
219     fontRuns.Clear();
220   }
221   else
222   {
223     fontRuns.Resize( numberOfRuns );
224     memcpy( fontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) );
225   }
226
227   mImpl->mGetFontCache.characterIndex = 0u;
228   mImpl->mGetFontCache.numberOfCharacters = 0u;
229   mImpl->mGetFontCache.firstRun = 0u;
230   mImpl->mGetFontCache.numberOfRuns = 0u;
231 }
232
233 Length LogicalModel::GetNumberOfFontRuns( CharacterIndex characterIndex,
234                                           Length numberOfCharacters ) const
235 {
236   GetRunCache& fontCache = mImpl->mGetFontCache;
237
238   // Set the character index and the number of characters into the cache.
239   fontCache.characterIndex = characterIndex;
240   fontCache.numberOfCharacters = numberOfCharacters;
241
242   if( ( 0u == characterIndex ) &&
243       ( mImpl->mText.Count() == numberOfCharacters ) )
244   {
245     fontCache.firstRun = 0u;
246     fontCache.numberOfRuns = mImpl->mFontRuns.Count();
247     return fontCache.numberOfRuns;
248   }
249
250   // Initialize the number of fonts and the index to the first font.
251   fontCache.firstRun = 0u;
252   fontCache.numberOfRuns = 0;
253   bool firstFontFound = false;
254
255   const Vector<FontRun>& modelFonts = mImpl->mFontRuns;
256   const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
257
258   // Traverse the fonts and count those fonts within the range of characters.
259   for( Vector<FontRun>::ConstIterator it = modelFonts.Begin(),
260          endIt = modelFonts.End();
261        it != endIt;
262        ++it )
263   {
264     const FontRun& font = *it;
265
266     if( ( font.characterRun.characterIndex + font.characterRun.numberOfCharacters > characterIndex ) &&
267         ( characterIndex + numberOfCharacters > font.characterRun.characterIndex ) )
268     {
269       firstFontFound = true;
270       ++fontCache.numberOfRuns;
271     }
272     else if( lastCharacterIndex <= font.characterRun.characterIndex )
273     {
274       // nothing else to do.
275       break;
276     }
277
278     if( !firstFontFound )
279     {
280       ++fontCache.firstRun;
281     }
282   }
283
284   return fontCache.numberOfRuns;
285 }
286
287 void LogicalModel::GetFontRuns( FontRun* fontRuns,
288                                 CharacterIndex characterIndex,
289                                 Length numberOfCharacters ) const
290 {
291   const Vector<FontRun>& modelFonts = mImpl->mFontRuns;
292   GetRunCache& fontCache = mImpl->mGetFontCache;
293
294   if( ( characterIndex != fontCache.characterIndex ) ||
295       ( numberOfCharacters != fontCache.numberOfCharacters ) )
296   {
297     GetNumberOfFontRuns( characterIndex,
298                          numberOfCharacters );
299   }
300
301   memcpy( fontRuns, modelFonts.Begin() + fontCache.firstRun, fontCache.numberOfRuns * sizeof( FontRun ) );
302 }
303
304 FontId LogicalModel::GetFont( CharacterIndex characterIndex ) const
305 {
306   for( Length index = 0u, length = mImpl->mFontRuns.Count(); index < length; ++index )
307   {
308     const FontRun* const fontRun = mImpl->mFontRuns.Begin() + index;
309
310     if( ( fontRun->characterRun.characterIndex <= characterIndex ) &&
311         ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) )
312     {
313       return fontRun->fontId;
314     }
315   }
316
317   return 0u;
318 }
319
320 void LogicalModel::SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
321                                      Length length )
322 {
323   Vector<LineBreakInfo>& modelLineBreakInfo = mImpl->mLineBreakInfo;
324
325   if( 0u == length )
326   {
327     modelLineBreakInfo.Clear();
328   }
329   else
330   {
331     modelLineBreakInfo.Resize( length );
332     memcpy( modelLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) );
333   }
334 }
335
336 void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
337                                      CharacterIndex characterIndex,
338                                      Length numberOfItems ) const
339 {
340   memcpy( lineBreakInfo, mImpl->mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) );
341 }
342
343 LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const
344 {
345   return *( mImpl->mLineBreakInfo.Begin() + characterIndex );
346 }
347
348 void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
349                                      Length length )
350 {
351   Vector<WordBreakInfo>& modelWordBreakInfo = mImpl->mWordBreakInfo;
352
353   if( 0u == length )
354   {
355     modelWordBreakInfo.Clear();
356   }
357   else
358   {
359     modelWordBreakInfo.Resize( length );
360     memcpy( modelWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) );
361   }
362 }
363
364 void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
365                                      CharacterIndex characterIndex,
366                                      Length numberOfItems ) const
367 {
368   memcpy( wordBreakInfo, mImpl->mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) );
369 }
370
371 WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const
372 {
373   return *( mImpl->mWordBreakInfo.Begin() + characterIndex );
374 }
375
376 void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
377                                          Length numberOfRuns )
378 {
379 }
380
381 Length LogicalModel::GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
382                                                        Length numberOfCharacters ) const
383 {
384   return 0u;
385 }
386
387 void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
388                                            CharacterIndex characterIndex,
389                                            Length numberOfCharacters ) const
390 {
391 }
392
393 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
394 {
395   return false;
396 }
397
398 void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
399                                           Length numberOfRuns )
400 {
401 }
402
403 CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
404 {
405   return 0u;
406 }
407
408 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
409 {
410   return 0u;
411 }
412
413 void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
414                                           CharacterIndex characterIndex,
415                                           Length numberOfCharacters ) const
416 {
417 }
418
419 void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
420                                           CharacterIndex characterIndex,
421                                           Length numberOfCharacters ) const
422 {
423 }
424
425 LogicalModel::~LogicalModel()
426 {
427   delete mImpl;
428 }
429
430 LogicalModel::LogicalModel()
431 : mImpl( NULL )
432 {
433   mImpl = new LogicalModel::Impl();
434 }
435
436 } // namespace Text
437
438 } // namespace Toolkit
439
440 } // namespace Dali