Bidi implementation
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / bidirectional-support-impl.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 // CLASS  HEADER
19 #include "bidirectional-support-impl.h"
20
21 // INTERNAL INCLUDES
22 #include <singleton-service-impl.h>
23
24 // EXTERNAL INCLUDES
25 #include <memory.h>
26 #include <fribidi/fribidi.h>
27
28 namespace Dali
29 {
30
31 namespace TextAbstraction
32 {
33
34 namespace Internal
35 {
36
37 struct BidirectionalSupport::BidirectionalInfo
38 {
39   FriBidiCharType* characterTypes;      ///< The type of each character (right, left, neutral, ...)
40   FriBidiLevel*    embeddedLevels;      ///< Embedded levels.
41   FriBidiParType   paragraphDirection;  ///< The paragraph's direction.
42 };
43
44 BidirectionalSupport::BidirectionalSupport()
45 : mPlugin( NULL ),
46   mParagraphBidirectionalInfo(),
47   mFreeIndices()
48 {
49 }
50
51 BidirectionalSupport::~BidirectionalSupport()
52 {
53   // free all resources.
54   for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
55          endIt = mParagraphBidirectionalInfo.End();
56        it != endIt;
57        ++it )
58   {
59     BidirectionalInfo* info = *it;
60
61     free( info->embeddedLevels );
62     free( info->characterTypes );
63     delete info;
64   }
65 }
66
67 TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
68 {
69   TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
70
71   SingletonService service( SingletonService::Get() );
72   if( service )
73   {
74     // Check whether the singleton is already created
75     BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
76     if(handle)
77     {
78       // If so, downcast the handle
79       BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
80       bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
81     }
82     else // create and register the object
83     {
84       bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
85       service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
86     }
87   }
88
89   return bidirectionalSupportHandle;
90 }
91
92 BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
93                                                 Length numberOfCharacters )
94 {
95   // Reserve memory for the paragraph's bidirectional info.
96   BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();
97
98   bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
99   bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );
100
101   // Retrieve the type of each character..
102   fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );
103
104   // Retrieve the paragraph's direction.
105   bidirectionalInfo->paragraphDirection = fribidi_get_par_direction( paragraph, numberOfCharacters );
106
107   // Retrieve the embedding levels.
108   fribidi_get_par_embedding_levels( paragraph, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels );
109
110   // Store the bidirectional info and return the index.
111   BidiInfoIndex index = 0u;
112   const std::size_t numberOfItems = mFreeIndices.Count();
113   if( numberOfItems != 0u )
114   {
115     Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;
116
117     index = *it;
118
119     mFreeIndices.Remove( it );
120
121     *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
122   }
123   else
124   {
125     index = static_cast<BidiInfoIndex>( numberOfItems );
126
127     mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
128   }
129
130   return index;
131 }
132
133 void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
134 {
135   if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
136   {
137     return;
138   }
139
140   // Retrieve the paragraph's bidirectional info.
141   Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
142   BidirectionalInfo* bidirectionalInfo = *it;
143
144   if( NULL != bidirectionalInfo )
145   {
146     // Free resources and destroy the container.
147     free( bidirectionalInfo->embeddedLevels );
148     free( bidirectionalInfo->characterTypes );
149     delete bidirectionalInfo;
150
151     *it = NULL;
152   }
153
154   // Add the index to the free indices vector.
155   mFreeIndices.PushBack( bidiInfoIndex );
156 }
157
158 void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
159                                     CharacterIndex firstCharacterIndex,
160                                     Length numberOfCharacters,
161                                     CharacterIndex* visualToLogicalMap )
162 {
163   const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
164
165   // Retrieve the paragraph's bidirectional info.
166   const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
167
168   // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
169   for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
170   {
171     visualToLogicalMap[ index ] = index;
172   }
173
174   // Copy embedded levels as fribidi_reorder_line() may change them.
175   const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof( FriBidiLevel );
176   FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( embeddedLevelsSize ) );
177   memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex,  embeddedLevelsSize );
178
179   // Reorder the line.
180   fribidi_reorder_line( flags,
181                         bidirectionalInfo->characterTypes + firstCharacterIndex,
182                         numberOfCharacters,
183                         0u,
184                         bidirectionalInfo->paragraphDirection,
185                         embeddedLevels,
186                         NULL,
187                         reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) );
188
189   // Free resources.
190   free( embeddedLevels );
191 }
192
193 } // namespace Internal
194
195 } // namespace TextAbstraction
196
197 } // namespace Dali