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/devel-api/common/singleton-service.h>
23 #include <dali/integration-api/debug.h>
24 #include <fribidi/fribidi.h>
29 namespace TextAbstraction
35 typedef unsigned char BidiDirection;
37 // Internal charcter's direction.
38 const BidiDirection LEFT_TO_RIGHT = 0u;
39 const BidiDirection NEUTRAL = 1u;
40 const BidiDirection RIGHT_TO_LEFT = 2u;
43 * @param[in] paragraphDirection The FriBiDi paragraph's direction.
45 * @return Whether the paragraph is right to left.
47 bool GetBidiParagraphDirection(FriBidiParType paragraphDirection)
49 switch(paragraphDirection)
51 case FRIBIDI_PAR_RTL: // Right-To-Left paragraph.
52 case FRIBIDI_PAR_WRTL: // Weak Right To Left paragraph.
56 case FRIBIDI_PAR_LTR: // Left-To-Right paragraph.
57 case FRIBIDI_PAR_ON: // DirectiOn-Neutral paragraph.
58 case FRIBIDI_PAR_WLTR: // Weak Left To Right paragraph.
67 BidiDirection GetBidiCharacterDirection(FriBidiCharType characterDirection)
69 switch(characterDirection)
71 case FRIBIDI_TYPE_LTR: // Left-To-Right letter.
75 case FRIBIDI_TYPE_AL: // Arabic Letter.
76 case FRIBIDI_TYPE_RTL: // Right-To-Left letter.
80 case FRIBIDI_TYPE_AN: // Arabic Numeral.
81 case FRIBIDI_TYPE_ES: // European number Separator.
82 case FRIBIDI_TYPE_ET: // European number Terminator.
83 case FRIBIDI_TYPE_EN: // European Numeral.
92 struct BidirectionalSupport::Plugin
95 * Stores bidirectional info per paragraph.
97 struct BidirectionalInfo
99 FriBidiCharType* characterTypes; ///< The type of each character (right, left, neutral, ...)
100 FriBidiLevel* embeddedLevels; ///< Embedded levels.
101 FriBidiParType paragraphDirection; ///< The paragraph's direction.
105 : mParagraphBidirectionalInfo(),
112 // free all resources.
113 for(Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
114 endIt = mParagraphBidirectionalInfo.End();
118 BidirectionalInfo* info = *it;
120 free(info->embeddedLevels);
121 free(info->characterTypes);
126 BidiInfoIndex CreateInfo(const Character* const paragraph,
127 Length numberOfCharacters,
128 bool matchLayoutDirection,
129 LayoutDirection::Type layoutDirection)
131 // Reserve memory for the paragraph's bidirectional info.
132 BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();
134 bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>(malloc(numberOfCharacters * sizeof(FriBidiCharType)));
135 if(!bidirectionalInfo->characterTypes)
137 delete bidirectionalInfo;
141 bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>(malloc(numberOfCharacters * sizeof(FriBidiLevel)));
142 if(!bidirectionalInfo->embeddedLevels)
144 free(bidirectionalInfo->characterTypes);
145 delete bidirectionalInfo;
149 // Retrieve the type of each character..
150 fribidi_get_bidi_types(paragraph, numberOfCharacters, bidirectionalInfo->characterTypes);
152 // Retrieve the paragraph's direction.
153 bidirectionalInfo->paragraphDirection = matchLayoutDirection == true ? (layoutDirection == LayoutDirection::RIGHT_TO_LEFT ? FRIBIDI_PAR_RTL : FRIBIDI_PAR_LTR) : (fribidi_get_par_direction(bidirectionalInfo->characterTypes, numberOfCharacters));
155 // Retrieve the embedding levels.
156 if(fribidi_get_par_embedding_levels(bidirectionalInfo->characterTypes, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels) == 0)
158 free(bidirectionalInfo->characterTypes);
159 delete bidirectionalInfo;
163 // Store the bidirectional info and return the index.
164 BidiInfoIndex index = 0u;
165 if(0u != mFreeIndices.Count())
167 Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;
171 mFreeIndices.Remove(it);
173 *(mParagraphBidirectionalInfo.Begin() + index) = bidirectionalInfo;
177 index = static_cast<BidiInfoIndex>(mParagraphBidirectionalInfo.Count());
179 mParagraphBidirectionalInfo.PushBack(bidirectionalInfo);
185 void DestroyInfo(BidiInfoIndex bidiInfoIndex)
187 if(bidiInfoIndex >= mParagraphBidirectionalInfo.Count())
192 // Retrieve the paragraph's bidirectional info.
193 Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
194 BidirectionalInfo* bidirectionalInfo = *it;
196 if(NULL != bidirectionalInfo)
198 // Free resources and destroy the container.
199 free(bidirectionalInfo->embeddedLevels);
200 free(bidirectionalInfo->characterTypes);
201 delete bidirectionalInfo;
206 // Add the index to the free indices vector.
207 mFreeIndices.PushBack(bidiInfoIndex);
210 void Reorder(BidiInfoIndex bidiInfoIndex,
211 CharacterIndex firstCharacterIndex,
212 Length numberOfCharacters,
213 CharacterIndex* visualToLogicalMap)
215 const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
217 // Retrieve the paragraph's bidirectional info.
218 const BidirectionalInfo* const bidirectionalInfo = *(mParagraphBidirectionalInfo.Begin() + bidiInfoIndex);
220 // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
221 for(CharacterIndex index = 0u; index < numberOfCharacters; ++index)
223 visualToLogicalMap[index] = index;
226 // Copy embedded levels as fribidi_reorder_line() may change them.
227 const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof(FriBidiLevel);
228 FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>(malloc(embeddedLevelsSize));
231 memcpy(embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex, embeddedLevelsSize);
234 if(fribidi_reorder_line(flags,
235 bidirectionalInfo->characterTypes + firstCharacterIndex,
238 bidirectionalInfo->paragraphDirection,
241 reinterpret_cast<FriBidiStrIndex*>(visualToLogicalMap)) == 0)
243 DALI_LOG_ERROR("fribidi_reorder_line is failed\n");
247 free(embeddedLevels);
251 bool GetMirroredText(Character* text,
252 CharacterDirection* directions,
253 Length numberOfCharacters) const
255 bool updated = false;
257 for(CharacterIndex index = 0u; index < numberOfCharacters; ++index)
259 // Get a reference to the character inside the text.
260 Character& character = *(text + index);
262 // Retrieve the mirrored character.
263 FriBidiChar mirroredCharacter = character;
264 bool mirrored = false;
265 if(*(directions + index))
267 mirrored = fribidi_get_mirror_char(character, &mirroredCharacter);
269 updated = updated || mirrored;
271 // Update the character inside the text.
272 character = mirroredCharacter;
278 bool GetParagraphDirection(BidiInfoIndex bidiInfoIndex) const
280 // Retrieve the paragraph's bidirectional info.
281 const BidirectionalInfo* const bidirectionalInfo = *(mParagraphBidirectionalInfo.Begin() + bidiInfoIndex);
283 return GetBidiParagraphDirection(bidirectionalInfo->paragraphDirection);
286 void GetCharactersDirection(BidiInfoIndex bidiInfoIndex,
287 CharacterDirection* directions,
288 Length numberOfCharacters)
290 const BidirectionalInfo* const bidirectionalInfo = *(mParagraphBidirectionalInfo.Begin() + bidiInfoIndex);
292 const CharacterDirection paragraphDirection = GetBidiParagraphDirection(bidirectionalInfo->paragraphDirection);
293 CharacterDirection previousDirection = paragraphDirection;
295 for(CharacterIndex index = 0u; index < numberOfCharacters; ++index)
297 CharacterDirection& characterDirection = *(directions + index);
298 CharacterDirection nextDirection = false;
300 characterDirection = false;
302 // Get the bidi direction.
303 const BidiDirection bidiDirection = GetBidiCharacterDirection(*(bidirectionalInfo->characterTypes + index));
305 if(RIGHT_TO_LEFT == bidiDirection)
307 characterDirection = true;
308 nextDirection = true;
310 else if(NEUTRAL == bidiDirection)
312 // For neutral characters it check's the next and previous directions.
313 // If they are equals set that direction. If they are not, sets the paragraph's direction.
314 // If there is no next, sets the paragraph's direction.
315 nextDirection = paragraphDirection;
317 // Look for the next non-neutral character.
318 Length nextIndex = index + 1u;
319 for(; nextIndex < numberOfCharacters; ++nextIndex)
321 BidiDirection nextBidiDirection = GetBidiCharacterDirection(*(bidirectionalInfo->characterTypes + nextIndex));
322 if(nextBidiDirection != NEUTRAL)
324 nextDirection = RIGHT_TO_LEFT == nextBidiDirection;
329 // Calculate the direction for all the neutral characters.
330 characterDirection = previousDirection == nextDirection ? previousDirection : paragraphDirection;
332 // Set the direction to all the neutral characters.
333 // The indices from currentIndex + 1u to nextIndex - 1u are neutral characters.
336 for(; index < nextIndex; ++index)
338 CharacterDirection& nextCharacterDirection = *(directions + index);
339 nextCharacterDirection = characterDirection;
342 // Set the direction of the next non-neutral character.
343 if(nextIndex < numberOfCharacters)
345 *(directions + nextIndex) = nextDirection;
349 previousDirection = nextDirection;
353 Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
354 Vector<BidiInfoIndex> mFreeIndices; ///< Stores indices of free positions in the bidirectional info vector.
357 BidirectionalSupport::BidirectionalSupport()
362 BidirectionalSupport::~BidirectionalSupport()
367 TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
369 TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
371 SingletonService service(SingletonService::Get());
374 // Check whether the singleton is already created
375 BaseHandle handle = service.GetSingleton(typeid(TextAbstraction::BidirectionalSupport));
378 // If so, downcast the handle
379 BidirectionalSupport* impl = dynamic_cast<Internal::BidirectionalSupport*>(handle.GetObjectPtr());
380 bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport(impl);
382 else // create and register the object
384 bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport(new BidirectionalSupport);
385 service.Register(typeid(bidirectionalSupportHandle), bidirectionalSupportHandle);
389 return bidirectionalSupportHandle;
392 BidiInfoIndex BidirectionalSupport::CreateInfo(const Character* const paragraph,
393 Length numberOfCharacters,
394 bool matchLayoutDirection,
395 Dali::LayoutDirection::Type layoutDirection)
399 return mPlugin->CreateInfo(paragraph,
401 matchLayoutDirection,
405 void BidirectionalSupport::DestroyInfo(BidiInfoIndex bidiInfoIndex)
409 mPlugin->DestroyInfo(bidiInfoIndex);
412 void BidirectionalSupport::Reorder(BidiInfoIndex bidiInfoIndex,
413 CharacterIndex firstCharacterIndex,
414 Length numberOfCharacters,
415 CharacterIndex* visualToLogicalMap)
419 mPlugin->Reorder(bidiInfoIndex,
425 bool BidirectionalSupport::GetMirroredText(Character* text,
426 CharacterDirection* directions,
427 Length numberOfCharacters)
431 return mPlugin->GetMirroredText(text, directions, numberOfCharacters);
434 bool BidirectionalSupport::GetParagraphDirection(BidiInfoIndex bidiInfoIndex) const
441 return mPlugin->GetParagraphDirection(bidiInfoIndex);
444 void BidirectionalSupport::GetCharactersDirection(BidiInfoIndex bidiInfoIndex,
445 CharacterDirection* directions,
446 Length numberOfCharacters)
450 mPlugin->GetCharactersDirection(bidiInfoIndex,
455 void BidirectionalSupport::CreatePlugin()
459 mPlugin = new Plugin();
463 } // namespace Internal
465 } // namespace TextAbstraction