Merge "Support moving of native-image-interface and image-operations to public-ap...
[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 namespace
35 {
36
37 /**
38  * @brief Get the lines of a paragraph.
39  *
40  * @param[in] paragraphInfo The paragraph.
41  * @param[in] lines The lines.
42  * @param[in] lineIndex Index pointing the first line to be checked.
43  * @param[out] firstLine Index to the first line of the paragraph.
44  * @param[out] numberOfLines The number of lines.
45  */
46 void GetLines( const BidirectionalParagraphInfoRun& paragraphInfo,
47                const Vector<LineRun>& lines,
48                unsigned int lineIndex,
49                unsigned int& firstLine,
50                unsigned int& numberOfLines )
51 {
52   firstLine = lineIndex;
53   numberOfLines = 0u;
54
55   const CharacterIndex lastCharacterIndex = paragraphInfo.characterRun.characterIndex + paragraphInfo.characterRun.numberOfCharacters;
56   bool firstLineFound = false;
57
58   for( Vector<LineRun>::ConstIterator it = lines.Begin() + lineIndex,
59          endIt = lines.End();
60        it != endIt;
61        ++it )
62   {
63     const LineRun& line = *it;
64
65     if( ( line.characterRun.characterIndex + line.characterRun.numberOfCharacters > paragraphInfo.characterRun.characterIndex ) &&
66         ( lastCharacterIndex > line.characterRun.characterIndex ) )
67     {
68       firstLineFound = true;
69       ++numberOfLines;
70     }
71     else if( lastCharacterIndex <= line.characterRun.characterIndex )
72     {
73       // nothing else to do.
74       break;
75     }
76
77     if( !firstLineFound )
78     {
79       ++firstLine;
80     }
81   }
82 }
83
84 } // namespace
85
86 void SetBidirectionalInfo( const Vector<Character>& text,
87                            const Vector<ScriptRun>& scripts,
88                            const Vector<LineBreakInfo>& lineBreakInfo,
89                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
90 {
91   // 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.
92   // From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK.
93
94   // Index pointing the first character of the current paragraph.
95   CharacterIndex paragraphCharacterIndex = 0u;
96
97   // Pointer to the text buffer.
98   const Character* textBuffer = text.Begin();
99
100   // Pointer to the line break info buffer.
101   const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
102
103   // The number of characters.
104   const Length numberOfCharacters = text.Count();
105
106   // Handle to the bidirectional info module in text-abstraction.
107   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
108
109   for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
110          endIt = scripts.End();
111        it != endIt;
112        ++it )
113   {
114     const ScriptRun& scriptRun = *it;
115     const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters;
116
117     if( TextAbstraction::IsRightToLeftScript( scriptRun.script ) && // The script is right to left.
118         ( lastScriptRunIndex > paragraphCharacterIndex ) )          // It isn't part of a previous paragraph.
119     {
120       // Find the paragraphs which contains this script run.
121       // Consider:
122       //  1) Different paragraphs may contain this script run.
123       //  ------||------------------- rtl sr ------------------------||-------------------
124       //  --||----- p -----||------------------ p -------------||-------- p ------||------
125       //
126       //  2) The paragraph which contains this script run may contain other right to left script runs.
127       //  -----||--- rtl sr ---||---- ltr sr ----||---------- rtl sr -----------||--------
128       //  -----||---------------------------------- p -----------------------------------|
129
130       while( lastScriptRunIndex > paragraphCharacterIndex )
131       {
132         // There is a paragraph which contains the current script.
133
134         Length index = paragraphCharacterIndex;
135         while( ( index < numberOfCharacters ) && ( paragraphCharacterIndex < lastScriptRunIndex ) )
136         {
137           if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) )
138           {
139             if( index >= scriptRun.characterRun.characterIndex )
140             {
141               // The Bidirectional run must have the same number of characters than the paragraph.
142               BidirectionalParagraphInfoRun bidirectionalRun;
143               bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
144               bidirectionalRun.characterRun.numberOfCharacters = ( index - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
145
146               // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
147               bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
148                                                                                          bidirectionalRun.characterRun.numberOfCharacters );
149
150               bidirectionalInfo.PushBack( bidirectionalRun );
151             }
152
153             // Update the character index of the next paragraph.
154             paragraphCharacterIndex = index + 1u;
155           }
156           ++index;
157         }
158
159         // The last character is always a must-break, so there is no need to check if there is characters left.
160       }
161     }
162   }
163 }
164
165 void ReplaceBidirectionalInfo( LogicalModel& model,
166                                CharacterIndex characterIndex,
167                                Length numberOfCharactersToRemove,
168                                Length numberOfCharactersToInsert )
169 {
170 }
171
172 void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
173                    Vector<LineRun>& lineRuns,
174                    Vector<BidirectionalLineInfoRun>& lineInfoRuns )
175 {
176   // Handle to the bidirectional info module in text-abstraction.
177   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
178
179   // Keep an index to the first line to be checked if it's contained inside the paragraph.
180   // Avoids check the lines from the beginning for each paragraph.
181   unsigned int lineIndex = 0u;
182
183   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
184          endIt = bidirectionalInfo.End();
185        it != endIt;
186        ++it )
187   {
188     const BidirectionalParagraphInfoRun& paragraphInfo = *it;
189     const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( paragraphInfo.bidirectionalInfoIndex );
190
191     // Get the lines for this paragraph.
192     unsigned int firstLine = 0u;
193     unsigned int numberOfLines = 0u;
194
195     // Get an index to the first line and the number of lines of the current paragraph.
196     GetLines( paragraphInfo,
197               lineRuns,
198               lineIndex,
199               firstLine,
200               numberOfLines );
201
202     lineIndex = firstLine + numberOfLines;
203
204     // Traverse the lines and reorder them
205     for( Vector<LineRun>::Iterator lineIt = lineRuns.Begin() + firstLine,
206            endLineIt = lineRuns.Begin() + firstLine + numberOfLines;
207            lineIt != endLineIt;
208          ++lineIt )
209     {
210       LineRun& line = *lineIt;
211
212       // Sets the paragraph's direction.
213       line.direction = direction;
214
215       // Creates a bidirectional info for the line run.
216       BidirectionalLineInfoRun lineInfoRun;
217       lineInfoRun.characterRun.characterIndex = line.characterRun.characterIndex;
218       lineInfoRun.characterRun.numberOfCharacters = line.characterRun.numberOfCharacters;
219       lineInfoRun.direction = direction;
220
221       // Allocate space for the conversion maps.
222       // The memory is freed after the visual to logical to visual conversion tables are built in the logical model.
223       lineInfoRun.visualToLogicalMap = reinterpret_cast<CharacterIndex*>( malloc( line.characterRun.numberOfCharacters * sizeof( CharacterIndex ) ) );
224
225       // Reorders the line.
226       bidirectionalSupport.Reorder( paragraphInfo.bidirectionalInfoIndex,
227                                     line.characterRun.characterIndex - paragraphInfo.characterRun.characterIndex,
228                                     line.characterRun.numberOfCharacters,
229                                     lineInfoRun.visualToLogicalMap );
230
231       // Push the run into the vector.
232       lineInfoRuns.PushBack( lineInfoRun );
233     }
234   }
235 }
236
237 void ReorderLines( LogicalModel& logicalModel,
238                    const VisualModel& visualModel,
239                    CharacterIndex characterIndex,
240                    Length numberOfCharactersToRemove,
241                    Length numberOfCharactersToInsert )
242 {
243 }
244
245 bool GetMirroredText( const Vector<Character>& text,
246                       Vector<Character>& mirroredText )
247 {
248   // Handle to the bidirectional info module in text-abstraction.
249   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
250
251   mirroredText = text;
252
253   return bidirectionalSupport.GetMirroredText( mirroredText.Begin(),
254                                                mirroredText.Count() );
255 }
256
257 void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
258                              Vector<CharacterDirection>& directions )
259 {
260   // Handle to the bidirectional info module in text-abstraction.
261   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
262
263   CharacterIndex index = 0u;
264   CharacterDirection* directionsBuffer = directions.Begin();
265   for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
266          endIt = bidirectionalInfo.End();
267        it != endIt;
268        ++it )
269   {
270     const BidirectionalParagraphInfoRun& paragraph = *it;
271
272     // Fills with left to right those paragraphs without right to left characters.
273     memset( directionsBuffer + index, false, ( paragraph.characterRun.characterIndex - index ) * sizeof( bool ) );
274     index += paragraph.characterRun.numberOfCharacters;
275
276     bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex,
277                                                  directionsBuffer + paragraph.characterRun.characterIndex,
278                                                  paragraph.characterRun.numberOfCharacters );
279   }
280
281   // Fills with left to right those paragraphs without right to left characters.
282   memset( directionsBuffer + index, false, ( directions.Count() - index ) * sizeof( bool ) );
283 }
284
285 } // namespace Text
286
287 } // namespace Toolkit
288
289 } // namespace Dali