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