TextView - Right to Left implementation.
[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 BidirectionalLineInfo::BidirectionalLineInfo()
67 : mCharacterParagraphIndex(),
68   mNumberOfCharacters(),
69   mText(),
70   mVisualToLogicalMap(),
71   mLogicalToVisualMap()
72 {
73 }
74
75 BidirectionalLineInfo::~BidirectionalLineInfo()
76 {
77 }
78
79 BidirectionalLineInfo::BidirectionalLineInfo( const BidirectionalLineInfo& info )
80 : mCharacterParagraphIndex( info.mCharacterParagraphIndex ),
81   mNumberOfCharacters( info.mNumberOfCharacters ),
82   mText( info.mText ),
83   mVisualToLogicalMap( info.mVisualToLogicalMap ),
84   mLogicalToVisualMap( info.mLogicalToVisualMap )
85 {
86 }
87
88 BidirectionalLineInfo& BidirectionalLineInfo::operator=( const BidirectionalLineInfo& info )
89 {
90   if( this != &info )
91   {
92     mCharacterParagraphIndex = info.mCharacterParagraphIndex;
93     mNumberOfCharacters = info.mNumberOfCharacters;
94     mText = info.mText;
95     mVisualToLogicalMap = info.mVisualToLogicalMap;
96     mLogicalToVisualMap = info.mLogicalToVisualMap;
97   }
98
99   return *this;
100 }
101
102 bool BeginsRightToLeftCharacter( const Text& text )
103 {
104   for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
105   {
106     Character::CharacterDirection direction = text[i].GetCharacterDirection();
107     if( direction != Character::Neutral )
108     {
109       return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak );
110     }
111   }
112
113   return false;
114 }
115
116 bool ContainsRightToLeftCharacter( const Dali::Text& text )
117 {
118   for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
119   {
120     Character::CharacterDirection direction = ( text[i] ).GetCharacterDirection();
121     if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) )
122     {
123       return true;
124     }
125   }
126
127   return false;
128 }
129
130 void ProcessBidirectionalText( Text& paragraph, BidirectionalParagraphInfo* info )
131 {
132   if( paragraph.IsEmpty() )
133   {
134     // nothing to do if the paragraph is empty.
135     return;
136   }
137
138   const std::size_t stringSize = paragraph.GetText().size();
139
140   // Text buffer in logical order. Coded in unicode.
141   info->mLogicalUnicodeBuffer.resize( stringSize + 1u, 0u );
142   FriBidiChar* logicalUnicodeBufferPointer = &info->mLogicalUnicodeBuffer[0u];
143
144   // Converts from utf8 to unicode.
145   const std::size_t length = fribidi_charset_to_unicode( FRIBIDI_CHAR_SET_UTF8, paragraph.GetText().c_str(), stringSize, logicalUnicodeBufferPointer );
146
147   // Character type buffer.
148   info->mCharactersTypeBuffer.resize( length, 0u );
149
150   // Levels buffer.
151   info->mLevelsBuffer.resize( length, 0u );
152
153   // Joining type buffer.
154   std::vector<FriBidiJoiningType> joiningTypeBuffer;
155   joiningTypeBuffer.resize( length, 0u );
156
157   // Pointers to the buffers.
158   FriBidiCharType* charactersTypeBufferPointer = &info->mCharactersTypeBuffer[0u];
159   FriBidiLevel* levelsBufferPointer = &info->mLevelsBuffer[0u];
160   FriBidiJoiningType* joiningTypeBufferPointer = &joiningTypeBuffer[0u];
161
162   // Retrieves the type of each character.
163   fribidi_get_bidi_types( logicalUnicodeBufferPointer, length, charactersTypeBufferPointer );
164
165   // Retrieves the paragraph direction.
166   info->mDirection = fribidi_get_par_direction( charactersTypeBufferPointer, length );
167
168   // Retrieve the embedding levels.
169   fribidi_get_par_embedding_levels( charactersTypeBufferPointer, length, &info->mDirection, levelsBufferPointer );
170
171   // Retrieve the joining types.
172   fribidi_get_joining_types( logicalUnicodeBufferPointer, length, joiningTypeBufferPointer );
173
174   fribidi_join_arabic( charactersTypeBufferPointer, length, levelsBufferPointer, joiningTypeBufferPointer );
175
176   const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
177
178   fribidi_shape( flags, levelsBufferPointer, length, joiningTypeBufferPointer, logicalUnicodeBufferPointer );
179
180   std::vector<char> bidiTextConverted;
181
182   bidiTextConverted.resize( length * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6.
183                                                 // Currently Dali doesn't support this UTF-8 extension. Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character.
184
185   fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, logicalUnicodeBufferPointer, length, &bidiTextConverted[0] );
186
187   paragraph = Text( &bidiTextConverted[0u] );
188 }
189
190 void ReorderLine( BidirectionalParagraphInfo* paragraphInfo,
191                   BidirectionalLineInfo* lineInfo )
192 {
193   const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
194
195   lineInfo->mVisualToLogicalMap.Resize( lineInfo->mNumberOfCharacters, 0u );
196   lineInfo->mLogicalToVisualMap.Resize( lineInfo->mNumberOfCharacters, 0u );
197
198   std::vector<FriBidiChar> visualUnicodeBuffer;
199   visualUnicodeBuffer.insert( visualUnicodeBuffer.end(),
200                               paragraphInfo->mLogicalUnicodeBuffer.begin() + lineInfo->mCharacterParagraphIndex,
201                               paragraphInfo->mLogicalUnicodeBuffer.begin() + ( lineInfo->mCharacterParagraphIndex + lineInfo->mNumberOfCharacters ) );
202
203   // Pointers to the buffers.
204   FriBidiCharType* charactersTypeBufferPointer = &paragraphInfo->mCharactersTypeBuffer[lineInfo->mCharacterParagraphIndex];
205   FriBidiLevel* levelsBufferPointer = &paragraphInfo->mLevelsBuffer[lineInfo->mCharacterParagraphIndex];
206   FriBidiChar* visualUnicodeBufferPointer = &visualUnicodeBuffer[0u];
207   FriBidiStrIndex* visualToLogicalMapPointer = &lineInfo->mVisualToLogicalMap[0u];
208
209   // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
210   for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index )
211   {
212     lineInfo->mVisualToLogicalMap[ index ] = index;
213   }
214
215   fribidi_reorder_line( flags,
216                         charactersTypeBufferPointer,
217                         lineInfo->mNumberOfCharacters,
218                         0u,
219                         paragraphInfo->mDirection,
220                         levelsBufferPointer,
221                         visualUnicodeBufferPointer,
222                         visualToLogicalMapPointer );
223
224   // Fill the logical to visual mapping table.
225   for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index )
226   {
227     lineInfo->mLogicalToVisualMap[ lineInfo->mVisualToLogicalMap[ index ] ] = index;
228   }
229
230   std::vector<char> bidiTextConverted;
231
232   bidiTextConverted.resize( lineInfo->mNumberOfCharacters * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6.
233                                                                        // Currently Dali doesn't support this UTF-8 extension.
234                                                                        // Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character.
235
236   fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, visualUnicodeBufferPointer, lineInfo->mNumberOfCharacters, &bidiTextConverted[0u] );
237
238   lineInfo->mText = Text( &bidiTextConverted[0u] );
239 }
240
241 } // namespace TextProcessor
242
243 } // namespace Internal
244
245 } // namespace Toolkit
246
247 } // namespace Dali