Merge branch 'tizen' into new_text
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-view / text-processor-bidirectional-info.cpp
1 /*
2  * Copyright (c) 2014 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/controls/text-view/text-processor-bidirectional-info.h>
20
21 namespace Dali
22 {
23
24 namespace Toolkit
25 {
26
27 namespace Internal
28 {
29
30 namespace TextProcessor
31 {
32
33 BidirectionalParagraphInfo::BidirectionalParagraphInfo()
34 : mDirection( FRIBIDI_TYPE_ON ),
35   mCharactersTypeBuffer(),
36   mLevelsBuffer(),
37   mLogicalUnicodeBuffer()
38 {
39 }
40
41 BidirectionalParagraphInfo::~BidirectionalParagraphInfo()
42 {
43 }
44
45 BidirectionalParagraphInfo::BidirectionalParagraphInfo( const BidirectionalParagraphInfo& info )
46 : mDirection( info.mDirection ),
47   mCharactersTypeBuffer( info.mCharactersTypeBuffer ),
48   mLevelsBuffer( info.mLevelsBuffer ),
49   mLogicalUnicodeBuffer( info.mLogicalUnicodeBuffer )
50 {
51 }
52
53 BidirectionalParagraphInfo& BidirectionalParagraphInfo::operator=( const BidirectionalParagraphInfo& info )
54 {
55   if( this != &info )
56   {
57     mDirection = info.mDirection;
58     mCharactersTypeBuffer = info.mCharactersTypeBuffer;
59     mLevelsBuffer = info.mLevelsBuffer;
60     mLogicalUnicodeBuffer = info.mLogicalUnicodeBuffer;
61   }
62
63   return *this;
64 }
65
66 bool BidirectionalParagraphInfo::IsRightToLeftParagraph() const
67 {
68   bool isRightToLeft = false;
69
70   switch( mDirection )
71   {
72     case FRIBIDI_PAR_LTR:  // Left-To-Right paragraph.
73     case FRIBIDI_PAR_ON:   // DirectiOn-Neutral paragraph.
74     case FRIBIDI_PAR_WLTR: // Weak Left To Right paragraph.
75     {
76       isRightToLeft = false;
77       break;
78     }
79     case FRIBIDI_PAR_RTL:  // Right-To-Left paragraph.
80     case FRIBIDI_PAR_WRTL: // Weak Right To Left paragraph.
81     {
82       isRightToLeft = true;
83       break;
84     }
85   }
86
87   return isRightToLeft;
88 }
89
90 BidirectionalLineInfo::BidirectionalLineInfo()
91 : mCharacterParagraphIndex(),
92   mNumberOfCharacters(),
93   mText(),
94   mVisualToLogicalMap(),
95   mLogicalToVisualMap()
96 {
97 }
98
99 BidirectionalLineInfo::~BidirectionalLineInfo()
100 {
101 }
102
103 BidirectionalLineInfo::BidirectionalLineInfo( const BidirectionalLineInfo& info )
104 : mCharacterParagraphIndex( info.mCharacterParagraphIndex ),
105   mNumberOfCharacters( info.mNumberOfCharacters ),
106   mText( info.mText ),
107   mVisualToLogicalMap( info.mVisualToLogicalMap ),
108   mLogicalToVisualMap( info.mLogicalToVisualMap )
109 {
110 }
111
112 BidirectionalLineInfo& BidirectionalLineInfo::operator=( const BidirectionalLineInfo& info )
113 {
114   if( this != &info )
115   {
116     mCharacterParagraphIndex = info.mCharacterParagraphIndex;
117     mNumberOfCharacters = info.mNumberOfCharacters;
118     mText = info.mText;
119     mVisualToLogicalMap = info.mVisualToLogicalMap;
120     mLogicalToVisualMap = info.mLogicalToVisualMap;
121   }
122
123   return *this;
124 }
125
126 bool BeginsRightToLeftCharacter( const Text& text )
127 {
128   for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
129   {
130     Character::CharacterDirection direction = text[i].GetCharacterDirection();
131     if( direction != Character::Neutral )
132     {
133       return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak );
134     }
135   }
136
137   return false;
138 }
139
140 bool ContainsRightToLeftCharacter( const Dali::Text& text )
141 {
142   for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
143   {
144     Character::CharacterDirection direction = ( text[i] ).GetCharacterDirection();
145     if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) )
146     {
147       return true;
148     }
149   }
150
151   return false;
152 }
153
154 void ProcessBidirectionalText( Text& paragraph, BidirectionalParagraphInfo* info )
155 {
156   if( paragraph.IsEmpty() )
157   {
158     // nothing to do if the paragraph is empty.
159     return;
160   }
161
162   const std::size_t stringSize = paragraph.GetText().size();
163
164   // Text buffer in logical order. Coded in unicode.
165   info->mLogicalUnicodeBuffer.resize( stringSize + 1u, 0u );
166   FriBidiChar* logicalUnicodeBufferPointer = &info->mLogicalUnicodeBuffer[0u];
167
168   // Converts from utf8 to unicode.
169   const std::size_t length = fribidi_charset_to_unicode( FRIBIDI_CHAR_SET_UTF8, paragraph.GetText().c_str(), stringSize, logicalUnicodeBufferPointer );
170
171   // Character type buffer.
172   info->mCharactersTypeBuffer.resize( length, 0u );
173
174   // Levels buffer.
175   info->mLevelsBuffer.resize( length, 0u );
176
177   // Joining type buffer.
178   std::vector<FriBidiJoiningType> joiningTypeBuffer;
179   joiningTypeBuffer.resize( length, 0u );
180
181   // Pointers to the buffers.
182   FriBidiCharType* charactersTypeBufferPointer = &info->mCharactersTypeBuffer[0u];
183   FriBidiLevel* levelsBufferPointer = &info->mLevelsBuffer[0u];
184   FriBidiJoiningType* joiningTypeBufferPointer = &joiningTypeBuffer[0u];
185
186   // Retrieves the type of each character.
187   fribidi_get_bidi_types( logicalUnicodeBufferPointer, length, charactersTypeBufferPointer );
188
189   // Retrieves the paragraph direction.
190   info->mDirection = fribidi_get_par_direction( charactersTypeBufferPointer, length );
191
192   // Retrieve the embedding levels.
193   fribidi_get_par_embedding_levels( charactersTypeBufferPointer, length, &info->mDirection, levelsBufferPointer );
194
195   // Retrieve the joining types.
196   fribidi_get_joining_types( logicalUnicodeBufferPointer, length, joiningTypeBufferPointer );
197
198   fribidi_join_arabic( charactersTypeBufferPointer, length, levelsBufferPointer, joiningTypeBufferPointer );
199
200   const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
201
202   fribidi_shape( flags, levelsBufferPointer, length, joiningTypeBufferPointer, logicalUnicodeBufferPointer );
203
204   std::vector<char> bidiTextConverted;
205
206   bidiTextConverted.resize( length * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6.
207                                                 // Currently Dali doesn't support this UTF-8 extension. Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character.
208
209   fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, logicalUnicodeBufferPointer, length, &bidiTextConverted[0] );
210
211   paragraph = Text( &bidiTextConverted[0u] );
212 }
213
214 void ReorderLine( BidirectionalParagraphInfo* paragraphInfo,
215                   BidirectionalLineInfo* lineInfo )
216 {
217   const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
218
219   lineInfo->mVisualToLogicalMap.Resize( lineInfo->mNumberOfCharacters, 0u );
220   lineInfo->mLogicalToVisualMap.Resize( lineInfo->mNumberOfCharacters, 0u );
221
222   std::vector<FriBidiChar> visualUnicodeBuffer;
223   visualUnicodeBuffer.insert( visualUnicodeBuffer.end(),
224                               paragraphInfo->mLogicalUnicodeBuffer.begin() + lineInfo->mCharacterParagraphIndex,
225                               paragraphInfo->mLogicalUnicodeBuffer.begin() + ( lineInfo->mCharacterParagraphIndex + lineInfo->mNumberOfCharacters ) );
226
227   // Pointers to the buffers.
228   FriBidiCharType* charactersTypeBufferPointer = &paragraphInfo->mCharactersTypeBuffer[lineInfo->mCharacterParagraphIndex];
229   FriBidiLevel* levelsBufferPointer = &paragraphInfo->mLevelsBuffer[lineInfo->mCharacterParagraphIndex];
230   FriBidiChar* visualUnicodeBufferPointer = &visualUnicodeBuffer[0u];
231   FriBidiStrIndex* visualToLogicalMapPointer = &lineInfo->mVisualToLogicalMap[0u];
232
233   // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
234   for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index )
235   {
236     lineInfo->mVisualToLogicalMap[ index ] = index;
237   }
238
239   fribidi_reorder_line( flags,
240                         charactersTypeBufferPointer,
241                         lineInfo->mNumberOfCharacters,
242                         0u,
243                         paragraphInfo->mDirection,
244                         levelsBufferPointer,
245                         visualUnicodeBufferPointer,
246                         visualToLogicalMapPointer );
247
248   // Fill the logical to visual mapping table.
249   for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index )
250   {
251     lineInfo->mLogicalToVisualMap[ lineInfo->mVisualToLogicalMap[ index ] ] = index;
252   }
253
254   std::vector<char> bidiTextConverted;
255
256   bidiTextConverted.resize( lineInfo->mNumberOfCharacters * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6.
257                                                                        // Currently Dali doesn't support this UTF-8 extension.
258                                                                        // Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character.
259
260   fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, visualUnicodeBufferPointer, lineInfo->mNumberOfCharacters, &bidiTextConverted[0u] );
261
262   lineInfo->mText = Text( &bidiTextConverted[0u] );
263 }
264
265 } // namespace TextProcessor
266
267 } // namespace Internal
268
269 } // namespace Toolkit
270
271 } // namespace Dali