TextModel - Clear the buffers if the number of items is zero.
[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 struct LogicalModel::Impl
40 {
41   Vector<Character>     mText;
42   Vector<ScriptRun>     mScriptRuns;
43   Vector<FontRun>       mFontRuns;
44   Vector<LineBreakInfo> mLineBreakInfo;
45   Vector<WordBreakInfo> mWordBreakInfo;
46 };
47
48 LogicalModelPtr LogicalModel::New()
49 {
50   return LogicalModelPtr( new LogicalModel() );
51 }
52
53 void LogicalModel::SetText( const Character* const text,
54                             Length numberOfCharacters )
55 {
56   Vector<Character>& modelText = mImpl->mText;
57
58   if( 0u == numberOfCharacters )
59   {
60     modelText.Clear();
61   }
62   else
63   {
64     modelText.Resize( numberOfCharacters );
65     memcpy( modelText.Begin(), text, numberOfCharacters * sizeof( Character ) );
66   }
67 }
68
69 Length LogicalModel::GetNumberOfCharacters() const
70 {
71   return mImpl->mText.Count();
72 }
73
74 void LogicalModel::GetText( CharacterIndex characterIndex,
75                             Character* text,
76                             Length numberOfCharacters ) const
77 {
78   Vector<Character>& modelText = mImpl->mText;
79   memcpy( text, modelText.Begin() + characterIndex, numberOfCharacters * sizeof( Character ) );
80 }
81
82 Character LogicalModel::GetCharacter( CharacterIndex characterIndex ) const
83 {
84   return mImpl->mText[characterIndex];
85 }
86
87 void LogicalModel::SetScripts( const ScriptRun* const scripts,
88                                Length numberOfRuns )
89 {
90   Vector<ScriptRun>& scriptRuns = mImpl->mScriptRuns;
91
92   if( 0u == numberOfRuns )
93   {
94     scriptRuns.Clear();
95   }
96   else
97   {
98     scriptRuns.Resize( numberOfRuns );
99     memcpy( scriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) );
100   }
101 }
102
103 Length LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex,
104                                             Length numberOfCharacters ) const
105 {
106   if( ( 0u == characterIndex ) && ( mImpl->mText.Count() == numberOfCharacters ) )
107   {
108     return mImpl->mScriptRuns.Count();
109   }
110
111   const CharacterIndex charcterEndIndex = characterIndex + numberOfCharacters;
112   Length numberOfScriptRuns = 0u;
113   bool firstIndexFound = false;
114
115   for( Length index = 0u, length = mImpl->mScriptRuns.Count(); index < length; ++index )
116   {
117     const ScriptRun* const scriptRun = mImpl->mScriptRuns.Begin() + index;
118
119     if( !firstIndexFound &&
120         ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
121     {
122       // The character index is within this script run.
123       // Starts the counter of script runs.
124       firstIndexFound = true;
125     }
126
127     if( firstIndexFound )
128     {
129       ++numberOfScriptRuns;
130       if( scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters > charcterEndIndex )
131       {
132         // This script run exceeds the given range. The number of scripts can be returned.
133         return numberOfScriptRuns;
134       }
135     }
136   }
137
138   return numberOfScriptRuns;
139 }
140
141 void LogicalModel::GetScriptRuns( ScriptRun* scriptRuns,
142                                   CharacterIndex characterIndex,
143                                   Length numberOfCharacters ) const
144 {
145   // A better implementation can cache the first script run and the number of then when the GetNumberOfScriptRuns() is called.
146
147   Length numberOfScriptRuns = GetNumberOfScriptRuns( characterIndex,
148                                                      numberOfCharacters );
149
150   for( Length index = 0u, length = mImpl->mScriptRuns.Count(); index < length; ++index )
151   {
152     const ScriptRun* const scriptRun = mImpl->mScriptRuns.Begin() + index;
153
154     if( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters )
155     {
156       memcpy( scriptRuns, scriptRun, sizeof( ScriptRun ) * numberOfScriptRuns );
157       return;
158     }
159   }
160 }
161
162 Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
163 {
164   // If this operation is too slow, consider a binary search.
165
166   for( Length index = 0u, length = mImpl->mScriptRuns.Count(); index < length; ++index )
167   {
168     const ScriptRun* const scriptRun = mImpl->mScriptRuns.Begin() + index;
169
170     if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
171         ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
172     {
173       return scriptRun->script;
174     }
175   }
176
177   return TextAbstraction::UNKNOWN;
178 }
179
180 void LogicalModel::SetFonts( const FontRun* const fonts,
181                              Length numberOfRuns )
182 {
183   Vector<FontRun>& fontRuns = mImpl->mFontRuns;
184
185   if( 0u == numberOfRuns )
186   {
187     fontRuns.Clear();
188   }
189   else
190   {
191     fontRuns.Resize( numberOfRuns );
192     memcpy( fontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) );
193   }
194 }
195
196 Length LogicalModel::GetNumberOfFontRuns( CharacterIndex characterIndex,
197                                           Length numberOfCharacters ) const
198 {
199   if( ( 0u == characterIndex ) && ( mImpl->mText.Count() == numberOfCharacters ) )
200   {
201     return mImpl->mFontRuns.Count();
202   }
203
204   const CharacterIndex charcterEndIndex = characterIndex + numberOfCharacters;
205   Length numberOfFontRuns = 0u;
206   bool firstIndexFound = false;
207
208   for( Length index = 0u, length = mImpl->mFontRuns.Count(); index < length; ++index )
209   {
210     const FontRun* const fontRun = mImpl->mFontRuns.Begin() + index;
211
212     if( !firstIndexFound &&
213         ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) )
214     {
215       // The character index is within this font run.
216       // Starts the counter of font runs.
217       firstIndexFound = true;
218     }
219
220     if( firstIndexFound )
221     {
222       ++numberOfFontRuns;
223       if( fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters > charcterEndIndex )
224       {
225         // This font run exceeds the given range. The number of fonts can be returned.
226         return numberOfFontRuns;
227       }
228     }
229   }
230
231   return numberOfFontRuns;
232 }
233
234 void LogicalModel::GetFontRuns( FontRun* fontRuns,
235                                 CharacterIndex characterIndex,
236                                 Length numberOfCharacters ) const
237 {
238   // A better implementation can cache the first font run and the number of then when the GetNumberOfFontRuns() is called.
239
240   Length numberOfFontRuns = GetNumberOfFontRuns( characterIndex,
241                                                  numberOfCharacters );
242
243   for( Length index = 0u, length = mImpl->mFontRuns.Count(); index < length; ++index )
244   {
245     const FontRun* const fontRun = mImpl->mFontRuns.Begin() + index;
246
247     if( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters )
248     {
249       memcpy( fontRuns, fontRun, sizeof( FontRun ) * numberOfFontRuns );
250       return;
251     }
252   }
253 }
254
255 FontId LogicalModel::GetFont( CharacterIndex characterIndex ) const
256 {
257   for( Length index = 0u, length = mImpl->mFontRuns.Count(); index < length; ++index )
258   {
259     const FontRun* const fontRun = mImpl->mFontRuns.Begin() + index;
260
261     if( ( fontRun->characterRun.characterIndex <= characterIndex ) &&
262         ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) )
263     {
264       return fontRun->fontId;
265     }
266   }
267
268   return 0u;
269 }
270
271 void LogicalModel::SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
272                                      Length length )
273 {
274   Vector<LineBreakInfo>& modelLineBreakInfo = mImpl->mLineBreakInfo;
275
276   if( 0u == length )
277   {
278     modelLineBreakInfo.Clear();
279   }
280   else
281   {
282     modelLineBreakInfo.Resize( length );
283     memcpy( modelLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) );
284   }
285 }
286
287 void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
288                                      CharacterIndex characterIndex,
289                                      Length numberOfItems ) const
290 {
291   memcpy( lineBreakInfo, mImpl->mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) );
292 }
293
294 LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const
295 {
296   return *( mImpl->mLineBreakInfo.Begin() + characterIndex );
297 }
298
299 void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
300                                      Length length )
301 {
302   Vector<WordBreakInfo>& modelWordBreakInfo = mImpl->mWordBreakInfo;
303
304   if( 0u == length )
305   {
306     modelWordBreakInfo.Clear();
307   }
308   else
309   {
310     modelWordBreakInfo.Resize( length );
311     memcpy( modelWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) );
312   }
313 }
314
315 void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
316                                      CharacterIndex characterIndex,
317                                      Length numberOfItems ) const
318 {
319   memcpy( wordBreakInfo, mImpl->mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) );
320 }
321
322 WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const
323 {
324   return *( mImpl->mWordBreakInfo.Begin() + characterIndex );
325 }
326
327 void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
328                                          Length numberOfRuns )
329 {
330 }
331
332 Length LogicalModel::GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
333                                                        Length numberOfCharacters ) const
334 {
335   return 0u;
336 }
337
338 void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
339                                            CharacterIndex characterIndex,
340                                            Length numberOfCharacters ) const
341 {
342 }
343
344 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
345 {
346   return false;
347 }
348
349 void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
350                                           Length numberOfRuns )
351 {
352 }
353
354 CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
355 {
356   return 0u;
357 }
358
359 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
360 {
361   return 0u;
362 }
363
364 void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
365                                           CharacterIndex characterIndex,
366                                           Length numberOfCharacters ) const
367 {
368 }
369
370 void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
371                                           CharacterIndex characterIndex,
372                                           Length numberOfCharacters ) const
373 {
374 }
375
376 LogicalModel::~LogicalModel()
377 {
378   delete mImpl;
379 }
380
381 LogicalModel::LogicalModel()
382 : mImpl( NULL )
383 {
384   mImpl = new LogicalModel::Impl();
385 }
386
387 } // namespace Text
388
389 } // namespace Toolkit
390
391 } // namespace Dali