Fix prevent issue - Dereference null return value
[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 namespace
38 {
39   typedef unsigned char BidiDirection;
40
41   // Internal charcter's direction.
42   const BidiDirection LEFT_TO_RIGHT = 0u;
43   const BidiDirection NEUTRAL = 1u;
44   const BidiDirection RIGHT_TO_LEFT = 2u;
45
46   /**
47    * @param[in] paragraphDirection The FriBiDi paragraph's direction.
48    *
49    * @return Whether the paragraph is right to left.
50    */
51   bool GetBidiParagraphDirection( FriBidiParType paragraphDirection )
52   {
53     switch( paragraphDirection )
54     {
55       case FRIBIDI_PAR_RTL:  // Right-To-Left paragraph.
56       case FRIBIDI_PAR_WRTL: // Weak Right To Left paragraph.
57       {
58         return true;
59       }
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.
63       {
64         return false;
65       }
66     }
67
68     return false;
69   }
70
71   BidiDirection GetBidiCharacterDirection( FriBidiCharType characterDirection )
72   {
73     switch( characterDirection )
74     {
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.
80       {
81         return LEFT_TO_RIGHT;
82       }
83       case FRIBIDI_TYPE_RTL: // Right-To-Left letter.
84       case FRIBIDI_TYPE_AL:  // Arabic Letter.
85       {
86         return RIGHT_TO_LEFT;
87       }
88     }
89
90     return NEUTRAL;
91   }
92 }
93
94 struct BidirectionalSupport::Plugin
95 {
96   /**
97    * Stores bidirectional info per paragraph.
98    */
99   struct BidirectionalInfo
100   {
101     FriBidiCharType* characterTypes;      ///< The type of each character (right, left, neutral, ...)
102     FriBidiLevel*    embeddedLevels;      ///< Embedded levels.
103     FriBidiParType   paragraphDirection;  ///< The paragraph's direction.
104   };
105
106   Plugin()
107   : mParagraphBidirectionalInfo(),
108     mFreeIndices()
109   {}
110
111   ~Plugin()
112   {
113     // free all resources.
114     for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
115            endIt = mParagraphBidirectionalInfo.End();
116          it != endIt;
117          ++it )
118     {
119       BidirectionalInfo* info = *it;
120
121       free( info->embeddedLevels );
122       free( info->characterTypes );
123       delete info;
124     }
125   }
126
127   BidiInfoIndex CreateInfo( const Character* const paragraph,
128                             Length numberOfCharacters )
129   {
130     // Reserve memory for the paragraph's bidirectional info.
131     BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();
132
133     bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
134     if( !bidirectionalInfo->characterTypes )
135     {
136       delete bidirectionalInfo;
137       return 0;
138     }
139
140     bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );
141     if( !bidirectionalInfo->embeddedLevels )
142     {
143       free( bidirectionalInfo->characterTypes );
144       delete bidirectionalInfo;
145       return 0;
146     }
147
148     // Retrieve the type of each character..
149     fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );
150
151     // Retrieve the paragraph's direction.
152     bidirectionalInfo->paragraphDirection = fribidi_get_par_direction( bidirectionalInfo->characterTypes, numberOfCharacters );
153
154     // Retrieve the embedding levels.
155     fribidi_get_par_embedding_levels( bidirectionalInfo->characterTypes, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels );
156
157     // Store the bidirectional info and return the index.
158     BidiInfoIndex index = 0u;
159     if( 0u != mFreeIndices.Count() )
160     {
161       Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;
162
163       index = *it;
164
165       mFreeIndices.Remove( it );
166
167       *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
168     }
169     else
170     {
171       index = static_cast<BidiInfoIndex>( mParagraphBidirectionalInfo.Count() );
172
173       mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
174     }
175
176     return index;
177   }
178
179   void DestroyInfo( BidiInfoIndex bidiInfoIndex )
180   {
181     if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
182     {
183       return;
184     }
185
186     // Retrieve the paragraph's bidirectional info.
187     Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
188     BidirectionalInfo* bidirectionalInfo = *it;
189
190     if( NULL != bidirectionalInfo )
191     {
192       // Free resources and destroy the container.
193       free( bidirectionalInfo->embeddedLevels );
194       free( bidirectionalInfo->characterTypes );
195       delete bidirectionalInfo;
196
197       *it = NULL;
198     }
199
200     // Add the index to the free indices vector.
201     mFreeIndices.PushBack( bidiInfoIndex );
202   }
203
204   void Reorder( BidiInfoIndex bidiInfoIndex,
205                 CharacterIndex firstCharacterIndex,
206                 Length numberOfCharacters,
207                 CharacterIndex* visualToLogicalMap )
208   {
209     const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
210
211     // Retrieve the paragraph's bidirectional info.
212     const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
213
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 )
216     {
217       visualToLogicalMap[ index ] = index;
218     }
219
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 ) );
223     if( embeddedLevels )
224     {
225       memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex,  embeddedLevelsSize );
226
227       // Reorder the line.
228       fribidi_reorder_line( flags,
229                             bidirectionalInfo->characterTypes + firstCharacterIndex,
230                             numberOfCharacters,
231                             0u,
232                             bidirectionalInfo->paragraphDirection,
233                             embeddedLevels,
234                             NULL,
235                             reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) );
236
237       // Free resources.
238       free( embeddedLevels );
239     }
240   }
241
242   bool GetMirroredText( Character* text,
243                         Length numberOfCharacters ) const
244   {
245     bool updated = false;
246
247     for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
248     {
249       // Get a reference to the character inside the text.
250       Character& character = *( text + index );
251
252       // Retrieve the mirrored character.
253       FriBidiChar mirroredCharacter = character;
254       const bool mirrored = fribidi_get_mirror_char( character, &mirroredCharacter );
255       updated = updated || mirrored;
256
257       // Update the character inside the text.
258       character = mirroredCharacter;
259     }
260
261     return updated;
262   }
263
264   bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
265   {
266     // Retrieve the paragraph's bidirectional info.
267     const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
268
269     return GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
270   }
271
272   void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
273                                CharacterDirection* directions,
274                                Length numberOfCharacters )
275   {
276     const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
277
278     const CharacterDirection paragraphDirection = GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
279     CharacterDirection previousDirection = paragraphDirection;
280
281     for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
282     {
283       CharacterDirection& characterDirection = *( directions + index );
284       characterDirection = false;
285
286       // Get the bidi direction.
287       const BidiDirection bidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + index ) );
288
289       if( RIGHT_TO_LEFT == bidiDirection )
290       {
291         characterDirection = true;
292       }
293       else if( NEUTRAL == bidiDirection )
294       {
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.
298
299         CharacterDirection nextDirection = paragraphDirection;
300         const Length nextIndex = index + 1u;
301         if( nextIndex < numberOfCharacters )
302         {
303           const BidiDirection nextBidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + nextIndex ) );
304
305           nextDirection = RIGHT_TO_LEFT == nextBidiDirection;
306         }
307
308         characterDirection = previousDirection == nextDirection ? previousDirection : paragraphDirection;
309       }
310
311       previousDirection = characterDirection;
312     }
313   }
314
315   Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
316   Vector<BidiInfoIndex>      mFreeIndices;                ///< Stores indices of free positions in the bidirectional info vector.
317 };
318
319 BidirectionalSupport::BidirectionalSupport()
320 : mPlugin( NULL )
321 {
322 }
323
324 BidirectionalSupport::~BidirectionalSupport()
325 {
326   delete mPlugin;
327 }
328
329 TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
330 {
331   TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
332
333   SingletonService service( SingletonService::Get() );
334   if( service )
335   {
336     // Check whether the singleton is already created
337     BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
338     if(handle)
339     {
340       // If so, downcast the handle
341       BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
342       bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
343     }
344     else // create and register the object
345     {
346       bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
347       service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
348     }
349   }
350
351   return bidirectionalSupportHandle;
352 }
353
354 BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
355                                                 Length numberOfCharacters )
356 {
357   CreatePlugin();
358
359   return mPlugin->CreateInfo( paragraph,
360                               numberOfCharacters );
361 }
362
363 void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
364 {
365   CreatePlugin();
366
367   mPlugin->DestroyInfo( bidiInfoIndex );
368 }
369
370 void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
371                                     CharacterIndex firstCharacterIndex,
372                                     Length numberOfCharacters,
373                                     CharacterIndex* visualToLogicalMap )
374 {
375   CreatePlugin();
376
377   mPlugin->Reorder( bidiInfoIndex,
378                     firstCharacterIndex,
379                     numberOfCharacters,
380                     visualToLogicalMap );
381 }
382
383 bool BidirectionalSupport::GetMirroredText( Character* text,
384                                             Length numberOfCharacters )
385 {
386   CreatePlugin();
387
388   return mPlugin->GetMirroredText( text, numberOfCharacters );
389 }
390
391 bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
392 {
393   if( !mPlugin )
394   {
395     return false;
396   }
397
398   return mPlugin->GetParagraphDirection( bidiInfoIndex );
399 }
400
401 void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
402                                                    CharacterDirection* directions,
403                                                    Length numberOfCharacters )
404 {
405   CreatePlugin();
406
407   mPlugin->GetCharactersDirection( bidiInfoIndex,
408                                    directions,
409                                    numberOfCharacters );
410 }
411
412 void BidirectionalSupport::CreatePlugin()
413 {
414   if( !mPlugin )
415   {
416     mPlugin = new Plugin();
417   }
418 }
419
420 } // namespace Internal
421
422 } // namespace TextAbstraction
423
424 } // namespace Dali