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 "bidirectional-support-impl.h"
22 #include <singleton-service-impl.h>
26 #include <fribidi/fribidi.h>
31 namespace TextAbstraction
39 typedef unsigned char BidiDirection;
41 // Internal charcter's direction.
42 const BidiDirection LEFT_TO_RIGHT = 0u;
43 const BidiDirection NEUTRAL = 1u;
44 const BidiDirection RIGHT_TO_LEFT = 2u;
47 * @param[in] paragraphDirection The FriBiDi paragraph's direction.
49 * @return Whether the paragraph is right to left.
51 bool GetBidiParagraphDirection( FriBidiParType paragraphDirection )
53 switch( paragraphDirection )
55 case FRIBIDI_PAR_RTL: // Right-To-Left paragraph.
56 case FRIBIDI_PAR_WRTL: // Weak Right To Left paragraph.
60 case FRIBIDI_PAR_LTR: // Left-To-Right paragraph.
61 case FRIBIDI_PAR_ON: // DirectiOn-Neutral paragraph.
62 case FRIBIDI_PAR_WLTR: // Weak Left To Right paragraph.
71 BidiDirection GetBidiCharacterDirection( FriBidiCharType characterDirection )
73 switch( characterDirection )
75 case FRIBIDI_TYPE_LTR: // Left-To-Right letter.
76 case FRIBIDI_TYPE_EN: // European Numeral.
77 case FRIBIDI_TYPE_AN: // Arabic Numeral.
78 case FRIBIDI_TYPE_ES: // European number Separator.
79 case FRIBIDI_TYPE_ET: // European number Terminator.
83 case FRIBIDI_TYPE_RTL: // Right-To-Left letter.
84 case FRIBIDI_TYPE_AL: // Arabic Letter.
94 struct BidirectionalSupport::Plugin
97 * Stores bidirectional info per paragraph.
99 struct BidirectionalInfo
101 FriBidiCharType* characterTypes; ///< The type of each character (right, left, neutral, ...)
102 FriBidiLevel* embeddedLevels; ///< Embedded levels.
103 FriBidiParType paragraphDirection; ///< The paragraph's direction.
107 : mParagraphBidirectionalInfo(),
113 // free all resources.
114 for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
115 endIt = mParagraphBidirectionalInfo.End();
119 BidirectionalInfo* info = *it;
121 free( info->embeddedLevels );
122 free( info->characterTypes );
127 BidiInfoIndex CreateInfo( const Character* const paragraph,
128 Length numberOfCharacters )
130 // Reserve memory for the paragraph's bidirectional info.
131 BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();
133 bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
134 if( !bidirectionalInfo->characterTypes )
136 delete bidirectionalInfo;
140 bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );
141 if( !bidirectionalInfo->embeddedLevels )
143 free( bidirectionalInfo->characterTypes );
144 delete bidirectionalInfo;
148 // Retrieve the type of each character..
149 fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );
151 // Retrieve the paragraph's direction.
152 bidirectionalInfo->paragraphDirection = fribidi_get_par_direction( bidirectionalInfo->characterTypes, numberOfCharacters );
154 // Retrieve the embedding levels.
155 fribidi_get_par_embedding_levels( bidirectionalInfo->characterTypes, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels );
157 // Store the bidirectional info and return the index.
158 BidiInfoIndex index = 0u;
159 if( 0u != mFreeIndices.Count() )
161 Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;
165 mFreeIndices.Remove( it );
167 *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
171 index = static_cast<BidiInfoIndex>( mParagraphBidirectionalInfo.Count() );
173 mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
179 void DestroyInfo( BidiInfoIndex bidiInfoIndex )
181 if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
186 // Retrieve the paragraph's bidirectional info.
187 Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
188 BidirectionalInfo* bidirectionalInfo = *it;
190 if( NULL != bidirectionalInfo )
192 // Free resources and destroy the container.
193 free( bidirectionalInfo->embeddedLevels );
194 free( bidirectionalInfo->characterTypes );
195 delete bidirectionalInfo;
200 // Add the index to the free indices vector.
201 mFreeIndices.PushBack( bidiInfoIndex );
204 void Reorder( BidiInfoIndex bidiInfoIndex,
205 CharacterIndex firstCharacterIndex,
206 Length numberOfCharacters,
207 CharacterIndex* visualToLogicalMap )
209 const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
211 // Retrieve the paragraph's bidirectional info.
212 const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
214 // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
215 for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
217 visualToLogicalMap[ index ] = index;
220 // Copy embedded levels as fribidi_reorder_line() may change them.
221 const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof( FriBidiLevel );
222 FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( embeddedLevelsSize ) );
225 memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex, embeddedLevelsSize );
228 fribidi_reorder_line( flags,
229 bidirectionalInfo->characterTypes + firstCharacterIndex,
232 bidirectionalInfo->paragraphDirection,
235 reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) );
238 free( embeddedLevels );
242 bool GetMirroredText( Character* text,
243 Length numberOfCharacters ) const
245 bool updated = false;
247 for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
249 // Get a reference to the character inside the text.
250 Character& character = *( text + index );
252 // Retrieve the mirrored character.
253 FriBidiChar mirroredCharacter = character;
254 const bool mirrored = fribidi_get_mirror_char( character, &mirroredCharacter );
255 updated = updated || mirrored;
257 // Update the character inside the text.
258 character = mirroredCharacter;
264 bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
266 // Retrieve the paragraph's bidirectional info.
267 const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
269 return GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
272 void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
273 CharacterDirection* directions,
274 Length numberOfCharacters )
276 const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
278 const CharacterDirection paragraphDirection = GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
279 CharacterDirection previousDirection = paragraphDirection;
281 for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
283 CharacterDirection& characterDirection = *( directions + index );
284 characterDirection = false;
286 // Get the bidi direction.
287 const BidiDirection bidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + index ) );
289 if( RIGHT_TO_LEFT == bidiDirection )
291 characterDirection = true;
293 else if( NEUTRAL == bidiDirection )
295 // For neutral characters it check's the next and previous directions.
296 // If they are equals set that direction. If they are not, sets the paragraph's direction.
297 // If there is no next, sets the paragraph's direction.
299 CharacterDirection nextDirection = paragraphDirection;
301 // Look for the next non-neutral character.
302 Length nextIndex = index + 1u;
303 for( ; nextIndex < numberOfCharacters; ++nextIndex )
305 BidiDirection nextBidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + nextIndex ) );
306 if( nextBidiDirection != NEUTRAL )
308 nextDirection = RIGHT_TO_LEFT == nextBidiDirection;
313 // Calculate the direction for all the neutral characters.
314 characterDirection = previousDirection == nextDirection ? previousDirection : paragraphDirection;
316 // Set the direction to all the neutral characters.
318 for( ; index < nextIndex; ++index )
320 CharacterDirection& nextCharacterDirection = *( directions + index );
321 nextCharacterDirection = characterDirection;
324 // Set the direction of the next non-neutral character.
325 if( nextIndex < numberOfCharacters )
327 *( directions + nextIndex ) = nextDirection;
331 previousDirection = characterDirection;
335 Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
336 Vector<BidiInfoIndex> mFreeIndices; ///< Stores indices of free positions in the bidirectional info vector.
339 BidirectionalSupport::BidirectionalSupport()
344 BidirectionalSupport::~BidirectionalSupport()
349 TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
351 TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
353 SingletonService service( SingletonService::Get() );
356 // Check whether the singleton is already created
357 BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
360 // If so, downcast the handle
361 BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
362 bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
364 else // create and register the object
366 bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
367 service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
371 return bidirectionalSupportHandle;
374 BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
375 Length numberOfCharacters )
379 return mPlugin->CreateInfo( paragraph,
380 numberOfCharacters );
383 void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
387 mPlugin->DestroyInfo( bidiInfoIndex );
390 void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
391 CharacterIndex firstCharacterIndex,
392 Length numberOfCharacters,
393 CharacterIndex* visualToLogicalMap )
397 mPlugin->Reorder( bidiInfoIndex,
400 visualToLogicalMap );
403 bool BidirectionalSupport::GetMirroredText( Character* text,
404 Length numberOfCharacters )
408 return mPlugin->GetMirroredText( text, numberOfCharacters );
411 bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
418 return mPlugin->GetParagraphDirection( bidiInfoIndex );
421 void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
422 CharacterDirection* directions,
423 Length numberOfCharacters )
427 mPlugin->GetCharactersDirection( bidiInfoIndex,
429 numberOfCharacters );
432 void BidirectionalSupport::CreatePlugin()
436 mPlugin = new Plugin();
440 } // namespace Internal
442 } // namespace TextAbstraction