Updates for const->constexpr
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / bidirectional-support.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 // FILE HEADER
19 #include <dali-toolkit/internal/text/bidirectional-support.h>
20
21 // EXTERNAL INCLUDES
22 #include <memory.h>
23 #include <dali/devel-api/text-abstraction/bidirectional-support.h>
24
25 namespace Dali
26 {
27
28 namespace Toolkit
29 {
30
31 namespace Text
32 {
33
34 void SetBidirectionalInfo( const Vector<Character>& text,
35                            const Vector<ScriptRun>& scripts,
36                            const Vector<LineBreakInfo>& lineBreakInfo,
37                            CharacterIndex startIndex,
38                            Length numberOfCharacters,
39                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
40                            bool matchSystemLanguageDirection,
41                            Dali::LayoutDirection::Type layoutDirection )
42 {
43   // Find where to insert the new paragraphs.
44   BidirectionalRunIndex bidiInfoIndex = 0u;
45   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
46          endIt = bidirectionalInfo.End();
47        it != endIt;
48        ++it )
49   {
50     const BidirectionalParagraphInfoRun& run = *it;
51
52     if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
53     {
54       // Found where to insert the bidi info.
55       break;
56     }
57     ++bidiInfoIndex;
58   }
59
60   // Traverse the script runs. If there is one with a right to left script, create the bidirectional info for the paragraph containing that script is needed.
61   // From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK.
62
63   // Index pointing the first character of the current paragraph.
64   CharacterIndex paragraphCharacterIndex = startIndex;
65
66   // Pointer to the text buffer.
67   const Character* textBuffer = text.Begin();
68
69   // Pointer to the line break info buffer.
70   const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
71
72   // Handle to the bidirectional info module in text-abstraction.
73   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
74
75   const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
76
77   bool hasRightToLeftScript = false;
78
79   for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
80          endIt = scripts.End();
81        it != endIt;
82        ++it )
83   {
84     const ScriptRun& scriptRun = *it;
85     const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters - 1u;
86
87     if( startIndex > lastScriptRunIndex )
88     {
89       // Skip the run as it has already been processed.
90       continue;
91     }
92
93     if( lastCharacter <= scriptRun.characterRun.characterIndex )
94     {
95       // Do not get bidirectional info beyond startIndex + numberOfCharacters.
96       break;
97     }
98
99     if( !hasRightToLeftScript && scriptRun.isRightToLeft )
100     {
101       // The script is right to left.
102       hasRightToLeftScript = true;
103     }
104
105     if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + lastScriptRunIndex ) )
106     {
107       // A new paragraph has been found.
108
109       if( hasRightToLeftScript )
110       {
111         // The Bidirectional run must have the same number of characters than the paragraph.
112         BidirectionalParagraphInfoRun bidirectionalRun;
113         bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
114         bidirectionalRun.characterRun.numberOfCharacters = ( lastScriptRunIndex - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
115
116         // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
117         bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
118                                                                                    bidirectionalRun.characterRun.numberOfCharacters,
119                                                                                    matchSystemLanguageDirection,
120                                                                                    layoutDirection );
121
122         bidirectionalRun.direction = bidirectionalSupport.GetParagraphDirection( bidirectionalRun.bidirectionalInfoIndex );
123
124         bidirectionalInfo.Insert( bidirectionalInfo.Begin() + bidiInfoIndex, bidirectionalRun );
125         ++bidiInfoIndex;
126       }
127
128       // Point to the next paragraph.
129       paragraphCharacterIndex = lastScriptRunIndex + 1u;
130
131       // Reset whether there is a right to left script.
132       hasRightToLeftScript = false;
133     }
134   }
135
136   // Update indices of the bidi runs.
137   for( Vector<BidirectionalParagraphInfoRun>::Iterator it = bidirectionalInfo.Begin() + bidiInfoIndex,
138          endIt = bidirectionalInfo.End();
139        it != endIt;
140        ++it )
141   {
142     BidirectionalParagraphInfoRun& run = *it;
143
144     run.characterRun.characterIndex += numberOfCharacters;
145   }
146 }
147
148 void ReorderLine( const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo,
149                   Vector<BidirectionalLineInfoRun>& lineInfoRuns,
150                   BidirectionalLineRunIndex bidiLineIndex,
151                   CharacterIndex startIndex,
152                   Length numberOfCharacters,
153                   CharacterDirection direction )
154 {
155   // Handle to the bidirectional info module in text-abstraction.
156   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
157
158   // Creates a bidirectional info for the line run.
159   BidirectionalLineInfoRun lineInfoRun;
160   lineInfoRun.characterRun.characterIndex = startIndex;
161   lineInfoRun.characterRun.numberOfCharacters = numberOfCharacters;
162   lineInfoRun.direction = direction;
163   lineInfoRun.isIdentity = true;
164
165   // Allocate space for the conversion maps.
166   // The memory is freed after the visual to logical to visual conversion tables are built in the logical model.
167   lineInfoRun.visualToLogicalMap = reinterpret_cast<CharacterIndex*>( malloc( numberOfCharacters * sizeof( CharacterIndex ) ) );
168
169   if( nullptr != lineInfoRun.visualToLogicalMap )
170   {
171     // Reorders the line.
172     bidirectionalSupport.Reorder( bidirectionalParagraphInfo.bidirectionalInfoIndex,
173                                   lineInfoRun.characterRun.characterIndex - bidirectionalParagraphInfo.characterRun.characterIndex,
174                                   lineInfoRun.characterRun.numberOfCharacters,
175                                   lineInfoRun.visualToLogicalMap );
176
177     // For those LTR lines inside a bidirectional paragraph.
178     // It will save to relayout the line after reordering.
179     for( unsigned int i=0; i<numberOfCharacters; ++i )
180     {
181       if( i != *( lineInfoRun.visualToLogicalMap + i ) )
182       {
183         lineInfoRun.isIdentity = false;
184         break;
185       }
186     }
187   }
188
189   // Push the run into the vector.
190   lineInfoRuns.Insert( lineInfoRuns.Begin() + bidiLineIndex, lineInfoRun );
191 }
192
193 bool GetMirroredText( const Vector<Character>& text,
194                       const Vector<CharacterDirection>& directions,
195                       const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
196                       CharacterIndex startIndex,
197                       Length numberOfCharacters,
198                       Vector<Character>& mirroredText )
199 {
200   bool hasTextMirrored = false;
201
202   // Handle to the bidirectional info module in text-abstraction.
203   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
204
205   mirroredText = text;
206
207   Character* mirroredTextBuffer = mirroredText.Begin();
208   CharacterDirection* directionsBuffer = directions.Begin();
209
210   CharacterIndex index = startIndex;
211   const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
212
213   // Traverse the paragraphs and mirror the right to left ones.
214   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
215          endIt = bidirectionalInfo.End();
216        it != endIt;
217        ++it )
218   {
219     const BidirectionalParagraphInfoRun& paragraph = *it;
220
221     if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
222     {
223       // Skip the paragraph as it has already been processed.
224       continue;
225     }
226
227     if( lastCharacter <= paragraph.characterRun.characterIndex )
228     {
229       // Do not get mirror characters beyond startIndex + numberOfCharacters.
230       break;
231     }
232
233     index += paragraph.characterRun.numberOfCharacters;
234     const bool tmpMirrored = bidirectionalSupport.GetMirroredText( mirroredTextBuffer + paragraph.characterRun.characterIndex,
235                                                                    directionsBuffer + paragraph.characterRun.characterIndex,
236                                                                    paragraph.characterRun.numberOfCharacters );
237
238     hasTextMirrored = hasTextMirrored || tmpMirrored;
239   }
240
241   return hasTextMirrored;
242 }
243
244 void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
245                              Length totalNumberOfCharacters,
246                              CharacterIndex startIndex,
247                              Length numberOfCharacters,
248                              Vector<CharacterDirection>& directions )
249 {
250   // Handle to the bidirectional info module in text-abstraction.
251   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
252
253   // Resize the vector.
254   directions.Resize( totalNumberOfCharacters );
255
256   // Whether the current buffer is being updated or is set from scratch.
257   const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
258
259   CharacterDirection* directionsBuffer = NULL;
260   Vector<CharacterDirection> newDirections;
261
262   if( updateCurrentBuffer )
263   {
264     newDirections.Resize( numberOfCharacters );
265     directionsBuffer = newDirections.Begin();
266   }
267   else
268   {
269     directionsBuffer = directions.Begin();
270   }
271
272   const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
273   CharacterIndex index = startIndex;
274
275   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
276          endIt = bidirectionalInfo.End();
277        it != endIt;
278        ++it )
279   {
280     const BidirectionalParagraphInfoRun& paragraph = *it;
281
282     if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
283     {
284       // Skip the paragraph as it has already been processed.
285       continue;
286     }
287
288     if( lastCharacter <= paragraph.characterRun.characterIndex )
289     {
290       // Do not get the character directions beyond startIndex + numberOfCharacters.
291       break;
292     }
293
294     // Set the directions of any previous left to right characters.
295     const Length numberOfLeftToRightCharacters = paragraph.characterRun.characterIndex - index;
296     if( numberOfLeftToRightCharacters > 0u )
297     {
298       memset( directionsBuffer + index - startIndex, false, numberOfLeftToRightCharacters * sizeof( bool ) );
299     }
300
301     // Set the directions of the bidirectional text.
302     bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex,
303                                                  directionsBuffer + paragraph.characterRun.characterIndex - startIndex,
304                                                  paragraph.characterRun.numberOfCharacters );
305
306     // Update the index.
307     index += paragraph.characterRun.numberOfCharacters + numberOfLeftToRightCharacters;
308   }
309
310   // Fills with left to right those paragraphs without right to left characters.
311   memset( directionsBuffer + index - startIndex, false, ( lastCharacter - index ) * sizeof( bool ) );
312
313   // If the direction info is updated, it needs to be inserted in the model.
314   if( updateCurrentBuffer )
315   {
316     // Insert the directions in the given buffer.
317     directions.Insert( directions.Begin() + startIndex,
318                        newDirections.Begin(),
319                        newDirections.End() );
320     directions.Resize( totalNumberOfCharacters );
321   }
322 }
323
324 } // namespace Text
325
326 } // namespace Toolkit
327
328 } // namespace Dali