X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Fbidirectional-support.cpp;h=fd85439866997f7df025ebea979790420dee0529;hp=5cf1ffb61dca7bc30248275b6ee99c039c921b8c;hb=06e563f8a982e25a0efe2d91c794657dc8e4bc4a;hpb=830f03638ec6ecd3b12ba3d9eb6419fdb3a3db09 diff --git a/dali-toolkit/internal/text/bidirectional-support.cpp b/dali-toolkit/internal/text/bidirectional-support.cpp index 5cf1ffb..fd85439 100644 --- a/dali-toolkit/internal/text/bidirectional-support.cpp +++ b/dali-toolkit/internal/text/bidirectional-support.cpp @@ -18,6 +18,10 @@ // FILE HEADER #include +// EXTERNAL INCLUDES +#include +#include + namespace Dali { @@ -27,31 +31,261 @@ namespace Toolkit namespace Text { +namespace +{ + +/** + * @brief Get the lines of a paragraph. + * + * @param[in] paragraphInfo The paragraph. + * @param[in] lines The lines. + * @param[in] lineIndex Index pointing the first line to be checked. + * @param[out] firstLine Index to the first line of the paragraph. + * @param[out] numberOfLines The number of lines. + */ +void GetLines( const BidirectionalParagraphInfoRun& paragraphInfo, + const Vector& lines, + unsigned int lineIndex, + unsigned int& firstLine, + unsigned int& numberOfLines ) +{ + firstLine = lineIndex; + numberOfLines = 0u; + + const CharacterIndex lastCharacterIndex = paragraphInfo.characterRun.characterIndex + paragraphInfo.characterRun.numberOfCharacters; + bool firstLineFound = false; + + for( Vector::ConstIterator it = lines.Begin() + lineIndex, + endIt = lines.End(); + it != endIt; + ++it ) + { + const LineRun& line = *it; + + if( ( line.characterRun.characterIndex + line.characterRun.numberOfCharacters > paragraphInfo.characterRun.characterIndex ) && + ( lastCharacterIndex > line.characterRun.characterIndex ) ) + { + firstLineFound = true; + ++numberOfLines; + } + else if( lastCharacterIndex <= line.characterRun.characterIndex ) + { + // nothing else to do. + break; + } + + if( !firstLineFound ) + { + ++firstLine; + } + } +} + +} // namespace + void SetBidirectionalInfo( const Vector& text, + const Vector& scripts, const Vector& lineBreakInfo, Vector& bidirectionalInfo ) { -} + // Traverse the script runs. If there is one with a right to left script, create the bidirectional info for the paragraph containing that script is needed. + // From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK. -void ReplaceBidirectionalInfo( LogicalModel& model, - CharacterIndex characterIndex, - Length numberOfCharactersToRemove, - Length numberOfCharactersToInsert ) -{ + // Index pointing the first character of the current paragraph. + CharacterIndex paragraphCharacterIndex = 0u; + + // Pointer to the text buffer. + const Character* textBuffer = text.Begin(); + + // Pointer to the line break info buffer. + const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin(); + + // The number of characters. + const Length numberOfCharacters = text.Count(); + + // Handle to the bidirectional info module in text-abstraction. + TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get(); + + for( Vector::ConstIterator it = scripts.Begin(), + endIt = scripts.End(); + it != endIt; + ++it ) + { + const ScriptRun& scriptRun = *it; + const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters; + + if( TextAbstraction::IsRightToLeftScript( scriptRun.script ) && // The script is right to left. + ( lastScriptRunIndex > paragraphCharacterIndex ) ) // It isn't part of a previous paragraph. + { + // Find the paragraphs which contains this script run. + // Consider: + // 1) Different paragraphs may contain this script run. + // ------||------------------- rtl sr ------------------------||------------------- + // --||----- p -----||------------------ p -------------||-------- p ------||------ + // + // 2) The paragraph which contains this script run may contain other right to left script runs. + // -----||--- rtl sr ---||---- ltr sr ----||---------- rtl sr -----------||-------- + // -----||---------------------------------- p -----------------------------------| + + while( lastScriptRunIndex > paragraphCharacterIndex ) + { + // There is a paragraph which contains the current script. + + Length index = paragraphCharacterIndex; + while( ( index < numberOfCharacters ) && ( paragraphCharacterIndex < lastScriptRunIndex ) ) + { + if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) ) + { + if( index >= scriptRun.characterRun.characterIndex ) + { + // The Bidirectional run must have the same number of characters than the paragraph. + BidirectionalParagraphInfoRun bidirectionalRun; + bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex; + bidirectionalRun.characterRun.numberOfCharacters = ( index - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah. + + // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run. + bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex, + bidirectionalRun.characterRun.numberOfCharacters ); + + bidirectionalInfo.PushBack( bidirectionalRun ); + } + + // Update the character index of the next paragraph. + paragraphCharacterIndex = index + 1u; + } + ++index; + } + + // The last character is always a must-break, so there is no need to check if there is characters left. + } + } + } } void ReorderLines( const Vector& bidirectionalInfo, - const Vector& lineRuns, + Vector& lineRuns, Vector& lineInfoRuns ) { + // Handle to the bidirectional info module in text-abstraction. + TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get(); + + // Keep an index to the first line to be checked if it's contained inside the paragraph. + // Avoids check the lines from the beginning for each paragraph. + unsigned int lineIndex = 0u; + + for( Vector::ConstIterator it = bidirectionalInfo.Begin(), + endIt = bidirectionalInfo.End(); + it != endIt; + ++it ) + { + const BidirectionalParagraphInfoRun& paragraphInfo = *it; + const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( paragraphInfo.bidirectionalInfoIndex ); + + // Get the lines for this paragraph. + unsigned int firstLine = 0u; + unsigned int numberOfLines = 0u; + + // Get an index to the first line and the number of lines of the current paragraph. + GetLines( paragraphInfo, + lineRuns, + lineIndex, + firstLine, + numberOfLines ); + + lineIndex = firstLine + numberOfLines; + + // Traverse the lines and reorder them + for( Vector::Iterator lineIt = lineRuns.Begin() + firstLine, + endLineIt = lineRuns.Begin() + firstLine + numberOfLines; + lineIt != endLineIt; + ++lineIt ) + { + LineRun& line = *lineIt; + + // Sets the paragraph's direction. + line.direction = direction; + + // Creates a bidirectional info for the line run. + BidirectionalLineInfoRun lineInfoRun; + lineInfoRun.characterRun.characterIndex = line.characterRun.characterIndex; + lineInfoRun.characterRun.numberOfCharacters = line.characterRun.numberOfCharacters; + lineInfoRun.direction = direction; + + // Allocate space for the conversion maps. + // The memory is freed after the visual to logical to visual conversion tables are built in the logical model. + lineInfoRun.visualToLogicalMap = reinterpret_cast( malloc( line.characterRun.numberOfCharacters * sizeof( CharacterIndex ) ) ); + + if( NULL != lineInfoRun.visualToLogicalMap ) + { + // Reorders the line. + bidirectionalSupport.Reorder( paragraphInfo.bidirectionalInfoIndex, + line.characterRun.characterIndex - paragraphInfo.characterRun.characterIndex, + line.characterRun.numberOfCharacters, + lineInfoRun.visualToLogicalMap ); + } + + // Push the run into the vector. + lineInfoRuns.PushBack( lineInfoRun ); + } + } +} + +bool GetMirroredText( const Vector& text, + Vector& mirroredText, + const Vector& bidirectionalInfo ) +{ + bool hasTextMirrored = false; + + // Handle to the bidirectional info module in text-abstraction. + TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get(); + + mirroredText = text; + + Character* mirroredTextBuffer = mirroredText.Begin(); + + // Traverse the paragraphs and mirror the right to left ones. + for( Vector::ConstIterator it = bidirectionalInfo.Begin(), + endIt = bidirectionalInfo.End(); + it != endIt; + ++it ) + { + const BidirectionalParagraphInfoRun& run = *it; + + const bool tmpMirrored = bidirectionalSupport.GetMirroredText( mirroredTextBuffer + run.characterRun.characterIndex, + run.characterRun.numberOfCharacters ); + + hasTextMirrored = hasTextMirrored || tmpMirrored; + } + + return hasTextMirrored; } -void ReorderLines( LogicalModel& logicalModel, - const VisualModel& visualModel, - CharacterIndex characterIndex, - Length numberOfCharactersToRemove, - Length numberOfCharactersToInsert ) +void GetCharactersDirection( const Vector& bidirectionalInfo, + Vector& directions ) { + // Handle to the bidirectional info module in text-abstraction. + TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get(); + + CharacterIndex index = 0u; + CharacterDirection* directionsBuffer = directions.Begin(); + for( Vector::ConstIterator it = bidirectionalInfo.Begin(), + endIt = bidirectionalInfo.End(); + it != endIt; + ++it ) + { + const BidirectionalParagraphInfoRun& paragraph = *it; + + // Fills with left to right those paragraphs without right to left characters. + memset( directionsBuffer + index, false, ( paragraph.characterRun.characterIndex - index ) * sizeof( bool ) ); + index += paragraph.characterRun.numberOfCharacters; + + bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex, + directionsBuffer + paragraph.characterRun.characterIndex, + paragraph.characterRun.numberOfCharacters ); + } + + // Fills with left to right those paragraphs without right to left characters. + memset( directionsBuffer + index, false, ( directions.Count() - index ) * sizeof( bool ) ); } } // namespace Text