+
+/**
+ * Sets a character of a line of a bidirectional paragraph in the new position.
+ *
+ * @param[in] wordsLayoutInfo Layout info of all the words of the paragraph.
+ * @param[in] index Index within the paragraph to the character to be set in the new position.
+ * @param[in,out] character Reference to the character in the new position.
+ */
+void SetCharacter( const TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo,
+ std::size_t index,
+ TextViewProcessor::CharacterLayoutInfo& character )
+{
+ // Traverse all the characters of the paragraph till the one pointed by index is found.
+ std::size_t traversedCharacters = 0u;
+ for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordsLayoutInfo.begin(),
+ wordEndIt = wordsLayoutInfo.end();
+ wordIt != wordEndIt;
+ ++wordIt )
+ {
+ const TextViewProcessor::WordLayoutInfo& word( *wordIt );
+
+ const std::size_t numberOfCharacters = word.mCharactersLayoutInfo.size();
+ if( index < traversedCharacters + numberOfCharacters )
+ {
+ character = *( word.mCharactersLayoutInfo.begin() + ( index - traversedCharacters ) );
+ return;
+ }
+ traversedCharacters += numberOfCharacters;
+ }
+}
+
+/**
+ * Reorders the layout info of each line of the paragraph.
+ *
+ * Uses the visual to logical conversion table to order the text, styles and character's layout (metrics).
+ *
+ * @param[in] characterGlobalIndex Index within the whole text of the first character of the paragraph.
+ * @param[in,out] rtlParagraph Layout info for the paragraph with rtl text.
+ * @param[in,out] relayoutData The text-view's data structures.
+ */
+void ReorderLayout( std::size_t characterGlobalIndex,
+ TextViewProcessor::ParagraphLayoutInfo& paragraph,
+ TextView::RelayoutData& relayoutData )
+{
+ // Clear any previous right to left layout.
+ if( NULL != paragraph.mRightToLeftLayout )
+ {
+ paragraph.mRightToLeftLayout->Clear();
+ paragraph.mRightToLeftLayout->mPreviousLayoutCleared = true;
+ }
+ else
+ {
+ // Create a new right to left layout if there isn't any.
+ paragraph.mRightToLeftLayout = new TextViewProcessor::RightToLeftParagraphLayout();
+ }
+
+ // Reorder Text and Styles.
+
+ // Reserve space for the styles.
+ paragraph.mRightToLeftLayout->mTextStyles.Reserve( paragraph.mTextStyles.Count() );
+
+ // Traverses all the bidirectional info per line.
+ for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
+ {
+ TextProcessor::BidirectionalLineInfo* info( *it );
+
+ const std::size_t characterParagraphIndex = info->mCharacterParagraphIndex;
+ const Vector<int>& visualToLogicalMap = info->mVisualToLogicalMap;
+
+ // The text can be appended as it's already reordered.
+ paragraph.mRightToLeftLayout->mText.Append( info->mText );
+
+ // The visual to logical map needs to be used to reorder the styles.
+ for( std::size_t index = 0u, size = visualToLogicalMap.Count(); index < size; ++index )
+ {
+ paragraph.mRightToLeftLayout->mTextStyles.PushBack( *( paragraph.mTextStyles.Begin() + ( characterParagraphIndex + *( visualToLogicalMap.Begin() + index ) ) ) );
+ }
+ }
+
+ // Reorder Layout Info.
+
+ // Reserve space for the new word layout.
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.reserve( paragraph.mWordsLayoutInfo.size() );
+
+ // Traverses all the bidirectional info per line.
+ for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
+ {
+ TextProcessor::BidirectionalLineInfo* info( *it );
+
+ // Reserve space for all characters.
+ TextViewProcessor::CharacterLayoutInfoContainer characters;
+ characters.resize( info->mNumberOfCharacters );
+
+ // Uses the visual to logical map to set every character in its new position.
+ for( std::size_t index = 0u; index < info->mNumberOfCharacters; ++index )
+ {
+ SetCharacter( paragraph.mWordsLayoutInfo,
+ info->mCharacterParagraphIndex + info->mVisualToLogicalMap[index],
+ *( characters.begin() + index ) );
+ }
+
+ // Sets the new 'x' position for each character.
+ // Updates the text-view's layout info table with the new position of the character.
+ float xPosition = 0.f;
+ std::size_t index = 0u;
+ for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it, ++index )
+ {
+ TextViewProcessor::CharacterLayoutInfo& character( *it );
+
+ // Set the 'x' position.
+ character.mPosition.x = xPosition;
+
+ // Update layout info table.
+ relayoutData.mCharacterLayoutInfoTable[characterGlobalIndex + info->mVisualToLogicalMap[index]].mPosition = character.mPosition;
+
+ // Update the position for the next character.
+ xPosition += character.mSize.width;
+ }
+
+ // Split the reordered text in words.
+ std::size_t previousPosition = 0u;
+ Vector<std::size_t> positions;
+ TextProcessor::SplitInWords( info->mText, positions );
+
+ // Whether last character is a word or a paragraph separator.
+ const std::size_t lastCharacterIndex = info->mText.GetLength() - 1u;
+ const bool isLastCharacterParagraphSeparator = info->mText.IsNewLine( lastCharacterIndex );
+ const bool isLastCharacterWordSeparator = info->mText.IsWhiteSpace( lastCharacterIndex );
+
+ // Sets the characters into the words they belong to.
+ for( Vector<std::size_t>::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it )
+ {
+ const std::size_t position = *it;
+
+ TextViewProcessor::WordLayoutInfo word;
+ word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
+ characters.begin() + previousPosition,
+ characters.begin() + position );
+
+ if( !word.mCharactersLayoutInfo.empty() )
+ {
+ // Updates the layout of the word.
+ TextViewProcessor::UpdateLayoutInfo( word );
+
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
+ }
+
+ // white space or new paragraph.
+ TextViewProcessor::WordLayoutInfo space;
+
+ space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(),
+ characters.begin() + position,
+ characters.begin() + position + 1u );
+
+ space.mType = TextViewProcessor::WordSeparator;
+
+ TextViewProcessor::UpdateLayoutInfo( space );
+
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space );
+
+ previousPosition = position + 1u;
+ }
+
+ // The last word.
+ if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() )
+ {
+ TextViewProcessor::WordLayoutInfo word;
+ word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
+ characters.begin() + previousPosition,
+ characters.end() );
+
+ if( isLastCharacterParagraphSeparator )
+ {
+ word.mType = TextViewProcessor::ParagraphSeparator;
+ }
+ else if( isLastCharacterWordSeparator )
+ {
+ word.mType = TextViewProcessor::WordSeparator;
+ }
+ TextViewProcessor::UpdateLayoutInfo( word );
+
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
+ }
+ }
+}
+
+/**
+ * Creates the bidirectional info needed to reorder each line of the paragraph.
+ *
+ * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
+ * @param[in,out] paragraph Layout info for the paragraph.
+ * @param[in] characterGlobalIndex Index to the character within the whole text.
+ * @param[in] lineLayoutInfoIndex Index to the table of lines.
+ */
+void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData,
+ TextViewProcessor::ParagraphLayoutInfo& paragraph,
+ std::size_t& characterGlobalIndex,
+ std::size_t& lineLayoutInfoIndex )
+{
+ const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
+ bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
+
+ // Clear previously created bidirectional info.
+ paragraph.ClearBidirectionalInfo();
+
+ // For each character, it sets the character's direction.
+
+ // Initialize the paragraph direction. Used to set the direction of weak characters.
+ const bool isParagraphRightToLeft = paragraph.mBidirectionalParagraphInfo->IsRightToLeftParagraph();
+ bool isPreviousRightToLeft = isParagraphRightToLeft;
+
+ for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
+ {
+ // Get the character's layout information (the one is shared with text-input)
+ Toolkit::TextView::CharacterLayoutInfo& info = *( relayoutData.mCharacterLayoutInfoTable.begin() + ( characterGlobalIndex + index ) );
+
+ // Gets the character's direction.
+ const Character::CharacterDirection direction = paragraph.mText[index].GetCharacterDirection();
+ if( Character::RightToLeft == direction )
+ {
+ info.mIsRightToLeftCharacter = true;
+ }
+ else if( Character::Neutral == direction )
+ {
+ // For neutral characters it check's the next and previous directions.
+ // If they are equals set that direction. If they are not, sets the paragraph direction.
+ // If there is no next, sets the previous direction.
+
+ // Check next character's direction.
+ bool isNextRightToLeft = isPreviousRightToLeft;
+ if( index < paragraph.mNumberOfCharacters - 1u )
+ {
+ const Character::CharacterDirection nextDirection = paragraph.mText[index + 1u].GetCharacterDirection();
+ isNextRightToLeft = Character::RightToLeft == nextDirection;
+ }
+
+ info.mIsRightToLeftCharacter = isPreviousRightToLeft == isNextRightToLeft ? isPreviousRightToLeft : isParagraphRightToLeft;
+ }
+ else
+ {
+ info.mIsRightToLeftCharacter = false;
+ }
+
+ isPreviousRightToLeft = info.mIsRightToLeftCharacter;
+ }
+
+ std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
+ wordIt != wordEndIt;
+ ++wordIt )
+ {
+ TextViewProcessor::WordLayoutInfo& word( *wordIt );
+
+ for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
+ characterIt != characterEndIt;
+ ++characterIt )
+ {
+ TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL;
+
+ // Check if there is a new line.
+ const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
+
+ if( newLine )
+ {
+ // Point to the next line.
+ ++lineLayoutInfoIndex;
+ if( lineLayoutInfoIndex >= lineLayoutInfoSize )
+ {
+ // Arrived at last line.
+ lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
+ }
+
+ // Number of characters of the line.
+ const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex;
+
+ // There is right to left characters in this line. It needs to be reordered.
+ bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo();
+ bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex;
+ bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters;
+
+ // Set all the Text's characters in the visual order and creates the mapping tables.
+ TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo,
+ bidirectionalLineInfo );
+
+ paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo );
+
+ for( std::size_t index = 0u; index < numberOfCharacters; ++index )
+ {
+ relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] );
+ relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] );
+ }
+ }
+
+ ++characterGlobalIndex;
+ ++characterParagraphIndex;
+ } // characters
+ } // words
+}
+
+void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData )
+{
+ // Reset conversion tables shared through public-api
+ relayoutData.mCharacterLogicalToVisualMap.clear();
+ relayoutData.mCharacterVisualToLogicalMap.clear();
+
+ std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
+ std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
+
+ for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
+ paragraphIt != paragraphEndIt;
+ ++paragraphIt )
+ {
+ TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
+
+ if( NULL != paragraph.mBidirectionalParagraphInfo )
+ {
+ // There is right to left text in this paragraph.
+
+ // Stores the current global character index as is needed in both functions.
+ const std::size_t currentGlobalIndex = characterGlobalIndex;
+
+ // Creates the bidirectional info needed to reorder each line of the paragraph.
+ CreateBidirectionalInfoForLines( relayoutData,
+ paragraph,
+ characterGlobalIndex,
+ lineLayoutInfoIndex );
+
+ // Reorder each line of the paragraph
+ ReorderLayout( currentGlobalIndex, paragraph, relayoutData );
+ }
+ else
+ {
+ // Identity in case the paragraph has no right to left text.
+ for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
+ {
+ const std::size_t globalIndex = characterGlobalIndex + index;
+ relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex );
+ relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex );
+ }
+ characterGlobalIndex += paragraph.mNumberOfCharacters;
+ }
+ } // paragraphs
+}
+
+float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth )