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