10b2a49a8a464dc33c870988fa89c189380e9fdb
[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 LogicalModelPtr LogicalModel::New()
35 {
36   return LogicalModelPtr( new LogicalModel() );
37 }
38
39 Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
40 {
41   // If this operation is too slow, consider a binary search.
42
43   for( Length index = 0u, length = mScriptRuns.Count(); index < length; ++index )
44   {
45     const ScriptRun* const scriptRun = mScriptRuns.Begin() + index;
46
47     if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
48         ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
49     {
50       return scriptRun->script;
51     }
52   }
53
54   return TextAbstraction::UNKNOWN;
55 }
56
57 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
58 {
59   if( characterIndex >= mCharacterDirections.Count() )
60   {
61     // The model has no right to left characters, so the vector of directions is void.
62     return false;
63   }
64
65   return *( mCharacterDirections.Begin() + characterIndex );
66 }
67
68 void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
69                                           Length numberOfRuns )
70 {
71   if( 0u == numberOfRuns )
72   {
73     mVisualToLogicalMap.Clear();
74     mLogicalToVisualMap.Clear();
75     mVisualToLogicalCursorMap.Clear();
76   }
77   else
78   {
79     const Length numberOfCharacters = mText.Count();
80     mVisualToLogicalMap.Resize( numberOfCharacters );
81     mLogicalToVisualMap.Resize( numberOfCharacters );
82
83     const Length numberOfCharactersPlus = numberOfCharacters + 1u;
84     mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
85
86     CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
87     CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
88
89     CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
90
91     CharacterIndex lastIndex = 0u;
92     for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
93     {
94       const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
95
96       if( lastIndex < bidiLineInfo.characterRun.characterIndex )
97       {
98         // Fill with the identity.
99         for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
100         {
101           *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
102         }
103       }
104
105       // Fill the conversion table of the run.
106       for( CharacterIndex index = 0u;
107            index < bidiLineInfo.characterRun.numberOfCharacters;
108            ++index, ++lastIndex )
109       {
110         *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
111       }
112     }
113
114     // Complete with the identity if there are some left to right characters after the last right to left.
115     for( ; lastIndex < numberOfCharacters; ++lastIndex )
116     {
117       *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
118     }
119
120     // Sets the logical to visual conversion map.
121     for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
122     {
123       *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
124     }
125
126     // Sets the visual to logical conversion map for cursor positions.
127
128     const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
129     BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
130     BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
131
132     const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
133
134     Length bidirectionalParagraphIndex = 0u;
135     bool isRightToLeftParagraph = false;
136     for( CharacterIndex index = 0u; index < numberOfCharactersPlus; ++index )
137     {
138       if( bidirectionalParagraph &&
139           ( bidirectionalParagraph->characterRun.characterIndex == index ) )
140       {
141         isRightToLeftParagraph = *( modelCharacterDirections + index );
142       }
143
144       if( 0u == index )
145       {
146         if( isRightToLeftParagraph )
147         {
148           *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
149         }
150         else // else logical position is zero.
151         {
152           *( modelVisualToLogicalCursorMap + index ) = 0u;
153         }
154       }
155       else if( numberOfCharacters == index )
156       {
157         if( isRightToLeftParagraph )
158         {
159           *( modelVisualToLogicalCursorMap + index ) = 0u;
160         }
161         else // else logical position is the number of characters.
162         {
163           *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
164         }
165       }
166       else
167       {
168         // Get the character indexed by  index - 1 and index
169         // and calculate the logical position according the directions of
170         // both characters and the direction of the paragraph.
171
172         const CharacterIndex previousIndex = index - 1u;
173         const CharacterIndex logicalPosition0 = *( modelVisualToLogicalMapBuffer + previousIndex );
174         const CharacterIndex logicalPosition1 = *( modelVisualToLogicalMapBuffer + index );
175
176         const CharacterDirection direction0 = *( modelCharacterDirections + logicalPosition0 );
177         const CharacterDirection direction1 = *( modelCharacterDirections + logicalPosition1 );
178
179         if( direction0 == direction1 )
180         {
181           // Both glyphs have the same direction.
182           if( direction0 )
183           {
184             *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
185           }
186           else
187           {
188             *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
189           }
190         }
191         else
192         {
193           if( isRightToLeftParagraph )
194           {
195             if( direction1 )
196             {
197               *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
198             }
199             else
200             {
201               *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
202             }
203           }
204           else
205           {
206             if( direction0 )
207             {
208               *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
209             }
210             else
211             {
212               *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
213             }
214           }
215         }
216       }
217
218       if( bidirectionalParagraph &&
219           ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
220       {
221         isRightToLeftParagraph = false;
222         ++bidirectionalParagraphIndex;
223         if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
224         {
225           bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
226         }
227         else
228         {
229           bidirectionalParagraph = NULL;
230         }
231       }
232     }
233   }
234 }
235
236 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
237 {
238   if( 0u == mVisualToLogicalMap.Count() )
239   {
240     // If there is no visual to logical info is because the whole text is left to right.
241     // Return the identity.
242     return visualCharacterIndex;
243   }
244
245   return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
246 }
247
248 void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters )
249 {
250   const Length totalNumberOfCharacters = mText.Count();
251
252   // Process the color runs.
253   Vector<ColorRun> removedColorRuns;
254   UpdateCharacterRuns<ColorRun>( index,
255                                  numberOfCharacters,
256                                  totalNumberOfCharacters,
257                                  mColorRuns,
258                                  removedColorRuns );
259 }
260
261 void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
262 {
263   unsigned int runIndex = 0u;
264   unsigned int lastRunIndex = 0u;
265   bool overriden = false;
266
267   // Set the text color.
268   for( Vector<ColorRun>::ConstIterator it = mColorRuns.Begin(),
269          endIt = mColorRuns.End();
270        it != endIt;
271        ++it, ++runIndex )
272   {
273     const ColorRun& colorRun = *it;
274
275     if( ( colorRun.characterRun.characterIndex <= index ) &&
276         ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) )
277     {
278       lastRunIndex = runIndex;
279       overriden = true;
280     }
281   }
282
283   // Set the text's color if it's overriden.
284   if( overriden )
285   {
286     style.textColor = ( *( mColorRuns.Begin() + lastRunIndex ) ).color;
287   }
288
289   runIndex = 0u;
290   overriden = false;
291 }
292
293 LogicalModel::~LogicalModel()
294 {
295 }
296
297 LogicalModel::LogicalModel()
298 {
299 }
300
301 } // namespace Text
302
303 } // namespace Toolkit
304
305 } // namespace Dali