+
+/**
+ * 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,out] rtlParagraph Layout info for the paragraph with rtl text.
+ */
+void ReorderLayout( TextViewProcessor::ParagraphLayoutInfo& paragraph )
+{
+ // 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.
+ float xPosition = 0.f;
+ for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it )
+ {
+ TextViewProcessor::CharacterLayoutInfo& character( *it );
+
+ character.mPosition.x = xPosition;
+ 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 );
+
+ // Sets the characters into the words they belong to.
+ for( Vector<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 );
+
+ 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() );
+
+ 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();
+
+ 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.
+
+ // Creates the bidirectional info needed to reorder each line of the paragraph.
+ CreateBidirectionalInfoForLines( relayoutData,
+ paragraph,
+ characterGlobalIndex,
+ lineLayoutInfoIndex );
+
+ // Reorder each line of the paragraph
+ ReorderLayout( paragraph );
+ }
+ 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
+}
+