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