2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/text/text-abstraction/bidirectional-support-impl.h>
22 #include <dali/internal/system/common/singleton-service-impl.h>
26 #include <fribidi/fribidi.h>
27 #include <dali/integration-api/debug.h>
32 namespace TextAbstraction
40 typedef unsigned char BidiDirection;
42 // Internal charcter's direction.
43 const BidiDirection LEFT_TO_RIGHT = 0u;
44 const BidiDirection NEUTRAL = 1u;
45 const BidiDirection RIGHT_TO_LEFT = 2u;
48 * @param[in] paragraphDirection The FriBiDi paragraph's direction.
50 * @return Whether the paragraph is right to left.
52 bool GetBidiParagraphDirection( FriBidiParType paragraphDirection )
54 switch( paragraphDirection )
56 case FRIBIDI_PAR_RTL: // Right-To-Left paragraph.
57 case FRIBIDI_PAR_WRTL: // Weak Right To Left paragraph.
61 case FRIBIDI_PAR_LTR: // Left-To-Right paragraph.
62 case FRIBIDI_PAR_ON: // DirectiOn-Neutral paragraph.
63 case FRIBIDI_PAR_WLTR: // Weak Left To Right paragraph.
72 BidiDirection GetBidiCharacterDirection( FriBidiCharType characterDirection )
74 switch( characterDirection )
76 case FRIBIDI_TYPE_LTR: // Left-To-Right letter.
80 case FRIBIDI_TYPE_AL: // Arabic Letter.
81 case FRIBIDI_TYPE_RTL: // Right-To-Left letter.
85 case FRIBIDI_TYPE_AN: // Arabic Numeral.
86 case FRIBIDI_TYPE_ES: // European number Separator.
87 case FRIBIDI_TYPE_ET: // European number Terminator.
88 case FRIBIDI_TYPE_EN: // European Numeral.
97 struct BidirectionalSupport::Plugin
100 * Stores bidirectional info per paragraph.
102 struct BidirectionalInfo
104 FriBidiCharType* characterTypes; ///< The type of each character (right, left, neutral, ...)
105 FriBidiLevel* embeddedLevels; ///< Embedded levels.
106 FriBidiParType paragraphDirection; ///< The paragraph's direction.
110 : mParagraphBidirectionalInfo(),
116 // free all resources.
117 for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
118 endIt = mParagraphBidirectionalInfo.End();
122 BidirectionalInfo* info = *it;
124 free( info->embeddedLevels );
125 free( info->characterTypes );
130 BidiInfoIndex CreateInfo( const Character* const paragraph,
131 Length numberOfCharacters,
132 bool matchSystemLanguageDirection,
133 LayoutDirection::Type layoutDirection )
135 // Reserve memory for the paragraph's bidirectional info.
136 BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();
138 bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
139 if( !bidirectionalInfo->characterTypes )
141 delete bidirectionalInfo;
145 bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );
146 if( !bidirectionalInfo->embeddedLevels )
148 free( bidirectionalInfo->characterTypes );
149 delete bidirectionalInfo;
153 // Retrieve the type of each character..
154 fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );
156 // Retrieve the paragraph's direction.
157 bidirectionalInfo->paragraphDirection = matchSystemLanguageDirection == true ?
158 ( layoutDirection == LayoutDirection::RIGHT_TO_LEFT ? FRIBIDI_PAR_RTL : FRIBIDI_PAR_LTR ) :
159 ( fribidi_get_par_direction( bidirectionalInfo->characterTypes, numberOfCharacters ) );
161 // Retrieve the embedding levels.
162 if (fribidi_get_par_embedding_levels( bidirectionalInfo->characterTypes, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels ) == 0)
164 free( bidirectionalInfo->characterTypes );
165 delete bidirectionalInfo;
169 // Store the bidirectional info and return the index.
170 BidiInfoIndex index = 0u;
171 if( 0u != mFreeIndices.Count() )
173 Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;
177 mFreeIndices.Remove( it );
179 *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
183 index = static_cast<BidiInfoIndex>( mParagraphBidirectionalInfo.Count() );
185 mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
191 void DestroyInfo( BidiInfoIndex bidiInfoIndex )
193 if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
198 // Retrieve the paragraph's bidirectional info.
199 Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
200 BidirectionalInfo* bidirectionalInfo = *it;
202 if( NULL != bidirectionalInfo )
204 // Free resources and destroy the container.
205 free( bidirectionalInfo->embeddedLevels );
206 free( bidirectionalInfo->characterTypes );
207 delete bidirectionalInfo;
212 // Add the index to the free indices vector.
213 mFreeIndices.PushBack( bidiInfoIndex );
216 void Reorder( BidiInfoIndex bidiInfoIndex,
217 CharacterIndex firstCharacterIndex,
218 Length numberOfCharacters,
219 CharacterIndex* visualToLogicalMap )
221 const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
223 // Retrieve the paragraph's bidirectional info.
224 const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
226 // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
227 for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
229 visualToLogicalMap[ index ] = index;
232 // Copy embedded levels as fribidi_reorder_line() may change them.
233 const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof( FriBidiLevel );
234 FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( embeddedLevelsSize ) );
237 memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex, embeddedLevelsSize );
240 if (fribidi_reorder_line( flags,
241 bidirectionalInfo->characterTypes + firstCharacterIndex,
244 bidirectionalInfo->paragraphDirection,
247 reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) ) == 0)
249 DALI_LOG_ERROR("fribidi_reorder_line is failed\n");
253 free( embeddedLevels );
257 bool GetMirroredText( Character* text,
258 CharacterDirection* directions,
259 Length numberOfCharacters ) const
261 bool updated = false;
263 for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
265 // Get a reference to the character inside the text.
266 Character& character = *( text + index );
268 // Retrieve the mirrored character.
269 FriBidiChar mirroredCharacter = character;
270 bool mirrored = false;
271 if( *( directions + index ) )
273 mirrored = fribidi_get_mirror_char( character, &mirroredCharacter );
275 updated = updated || mirrored;
277 // Update the character inside the text.
278 character = mirroredCharacter;
284 bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
286 // Retrieve the paragraph's bidirectional info.
287 const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
289 return GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
292 void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
293 CharacterDirection* directions,
294 Length numberOfCharacters )
296 const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
298 const CharacterDirection paragraphDirection = GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
299 CharacterDirection previousDirection = paragraphDirection;
301 for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
303 CharacterDirection& characterDirection = *( directions + index );
304 CharacterDirection nextDirection = false;
306 characterDirection = false;
308 // Get the bidi direction.
309 const BidiDirection bidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + index ) );
311 if( RIGHT_TO_LEFT == bidiDirection )
313 characterDirection = true;
314 nextDirection = true;
316 else if( NEUTRAL == bidiDirection )
318 // For neutral characters it check's the next and previous directions.
319 // If they are equals set that direction. If they are not, sets the paragraph's direction.
320 // If there is no next, sets the paragraph's direction.
321 nextDirection = paragraphDirection;
323 // Look for the next non-neutral character.
324 Length nextIndex = index + 1u;
325 for( ; nextIndex < numberOfCharacters; ++nextIndex )
327 BidiDirection nextBidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + nextIndex ) );
328 if( nextBidiDirection != NEUTRAL )
330 nextDirection = RIGHT_TO_LEFT == nextBidiDirection;
335 // Calculate the direction for all the neutral characters.
336 characterDirection = previousDirection == nextDirection ? previousDirection : paragraphDirection;
338 // Set the direction to all the neutral characters.
339 // The indices from currentIndex + 1u to nextIndex - 1u are neutral characters.
342 for( ; index < nextIndex; ++index )
344 CharacterDirection& nextCharacterDirection = *( directions + index );
345 nextCharacterDirection = characterDirection;
348 // Set the direction of the next non-neutral character.
349 if( nextIndex < numberOfCharacters )
351 *( directions + nextIndex ) = nextDirection;
355 previousDirection = nextDirection;
359 Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
360 Vector<BidiInfoIndex> mFreeIndices; ///< Stores indices of free positions in the bidirectional info vector.
363 BidirectionalSupport::BidirectionalSupport()
368 BidirectionalSupport::~BidirectionalSupport()
373 TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
375 TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
377 SingletonService service( SingletonService::Get() );
380 // Check whether the singleton is already created
381 BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
384 // If so, downcast the handle
385 BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
386 bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
388 else // create and register the object
390 bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
391 service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
395 return bidirectionalSupportHandle;
398 BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
399 Length numberOfCharacters,
400 bool matchSystemLanguageDirection,
401 Dali::LayoutDirection::Type layoutDirection )
405 return mPlugin->CreateInfo( paragraph,
407 matchSystemLanguageDirection,
411 void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
415 mPlugin->DestroyInfo( bidiInfoIndex );
418 void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
419 CharacterIndex firstCharacterIndex,
420 Length numberOfCharacters,
421 CharacterIndex* visualToLogicalMap )
425 mPlugin->Reorder( bidiInfoIndex,
428 visualToLogicalMap );
431 bool BidirectionalSupport::GetMirroredText( Character* text,
432 CharacterDirection* directions,
433 Length numberOfCharacters )
437 return mPlugin->GetMirroredText( text, directions, numberOfCharacters );
440 bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
447 return mPlugin->GetParagraphDirection( bidiInfoIndex );
450 void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
451 CharacterDirection* directions,
452 Length numberOfCharacters )
456 mPlugin->GetCharactersDirection( bidiInfoIndex,
458 numberOfCharacters );
461 void BidirectionalSupport::CreatePlugin()
465 mPlugin = new Plugin();
469 } // namespace Internal
471 } // namespace TextAbstraction