return *( mCharacterDirections.Begin() + characterIndex );
}
-void LogicalModel::SetVisualToLogicalMap( CharacterIndex startIndex,
- Length numberOfCharacters )
+CharacterIndex LogicalModel::GetLogicalCursorIndex( CharacterIndex visualCursorIndex )
{
- mVisualToLogicalMap.Resize( numberOfCharacters );
+ // The total number of characters.
+ const Length numberOfCharacters = mText.Count();
- CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
+ const bool fetch = FetchBidirectionalLineInfo( visualCursorIndex );
+ if( !fetch )
+ {
+ // The character is not inside a bidi line.
+ return visualCursorIndex;
+ }
- const BidirectionalLineInfoRun* const bidirectionalInfo = mBidirectionalLineInfo.Begin();
- const Length numberOfRuns = mBidirectionalLineInfo.Count();
+ // The character's directions buffer.
+ const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
- CharacterIndex lastIndex = startIndex;
- for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
- {
- const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
+ // The bidirectional line info.
+ const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
- if( bidiLineInfo.characterRun.characterIndex + bidiLineInfo.characterRun.numberOfCharacters <= startIndex )
- {
- // Skip this paragraph. It has been already processed.
- continue;
- }
+ // Whether the paragraph starts with a right to left character.
+ const bool isRightToLeftParagraph = bidirectionalLineInfo->direction;
- if( lastIndex < bidiLineInfo.characterRun.characterIndex )
+ CharacterIndex logicalCursorIndex = 0u;
+
+ if( 0u == visualCursorIndex )
+ {
+ if( isRightToLeftParagraph )
{
- // Fill with the identity.
- for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
- {
- *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
- }
+ logicalCursorIndex = numberOfCharacters;
}
-
- // Fill the conversion table of the run.
- for( CharacterIndex index = 0u;
- index < bidiLineInfo.characterRun.numberOfCharacters;
- ++index, ++lastIndex )
+ else // else logical position is zero.
{
- *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
+ logicalCursorIndex = 0u;
}
}
-
- // Complete with the identity if there are some left to right characters after the last right to left.
- for( ; lastIndex < numberOfCharacters; ++lastIndex )
+ else if( numberOfCharacters == visualCursorIndex )
{
- *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
- }
-
- // Sets the visual to logical conversion map for cursor positions.
- const Length numberOfCharactersPlusOne = numberOfCharacters + 1u;
- mVisualToLogicalCursorMap.Resize( numberOfCharactersPlusOne );
-
- CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
-
- const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
- BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
- BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
-
- const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
-
- Length bidirectionalParagraphIndex = 0u;
- bool isRightToLeftParagraph = false;
- for( CharacterIndex index = startIndex; index < numberOfCharactersPlusOne; ++index )
- {
- if( bidirectionalParagraph &&
- ( bidirectionalParagraph->characterRun.characterIndex == index ) )
+ if( isRightToLeftParagraph )
{
- isRightToLeftParagraph = *( modelCharacterDirections + index );
+ logicalCursorIndex = 0u;
}
-
- if( 0u == index )
+ else // else logical position is the number of characters.
{
- if( isRightToLeftParagraph )
- {
- *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
- }
- else // else logical position is zero.
- {
- *( modelVisualToLogicalCursorMap + index ) = 0u;
- }
+ logicalCursorIndex = numberOfCharacters;
}
- else if( numberOfCharacters == index )
+ }
+ else
+ {
+ // Get the character indexed by index - 1 and index
+ // and calculate the logical position according the directions of
+ // both characters and the direction of the paragraph.
+
+ const CharacterIndex previousVisualCursorIndex = visualCursorIndex - 1u;
+ const CharacterIndex previousLogicalCursorIndex = *( bidirectionalLineInfo->visualToLogicalMap + previousVisualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
+ const CharacterIndex currentLogicalCursorIndex = *( bidirectionalLineInfo->visualToLogicalMap + visualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
+
+ const CharacterDirection previousCharacterDirection = *( modelCharacterDirections + previousLogicalCursorIndex );
+ const CharacterDirection currentCharacterDirection = *( modelCharacterDirections + currentLogicalCursorIndex );
+
+ if( previousCharacterDirection == currentCharacterDirection )
{
- if( isRightToLeftParagraph )
+ // Both glyphs have the same direction.
+ if( previousCharacterDirection )
{
- *( modelVisualToLogicalCursorMap + index ) = 0u;
+ logicalCursorIndex = previousLogicalCursorIndex;
}
- else // else logical position is the number of characters.
+ else
{
- *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
+ logicalCursorIndex = currentLogicalCursorIndex;
}
}
else
{
- // Get the character indexed by index - 1 and index
- // and calculate the logical position according the directions of
- // both characters and the direction of the paragraph.
-
- const CharacterIndex previousIndex = index - 1u;
- const CharacterIndex logicalPosition0 = *( modelVisualToLogicalMapBuffer + previousIndex );
- const CharacterIndex logicalPosition1 = *( modelVisualToLogicalMapBuffer + index );
-
- const CharacterDirection direction0 = *( modelCharacterDirections + logicalPosition0 );
- const CharacterDirection direction1 = *( modelCharacterDirections + logicalPosition1 );
-
- if( direction0 == direction1 )
+ if( isRightToLeftParagraph )
{
- // Both glyphs have the same direction.
- if( direction0 )
+ if( currentCharacterDirection )
{
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
+ logicalCursorIndex = currentLogicalCursorIndex + 1u;
}
else
{
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
+ logicalCursorIndex = previousLogicalCursorIndex;
}
}
else
{
- if( isRightToLeftParagraph )
+ if( previousCharacterDirection )
{
- if( direction1 )
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
- }
- else
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
- }
+ logicalCursorIndex = currentLogicalCursorIndex;
}
else
{
- if( direction0 )
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
- }
- else
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
- }
+ logicalCursorIndex = previousLogicalCursorIndex + 1u;
}
}
}
+ }
+
+ return logicalCursorIndex;
+}
- if( bidirectionalParagraph &&
- ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
+CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex )
+{
+ const bool fetch = FetchBidirectionalLineInfo( visualCharacterIndex );
+ if( !fetch )
+ {
+ // The character is not inside a bidi line.
+ return visualCharacterIndex;
+ }
+
+ // The bidirectional line info.
+ const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
+
+ return *( bidirectionalLineInfo->visualToLogicalMap + visualCharacterIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
+}
+
+bool LogicalModel::FetchBidirectionalLineInfo( CharacterIndex characterIndex )
+{
+ // The number of bidirectional lines.
+ const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count();
+
+ if( 0u == numberOfBidirectionalLines )
+ {
+ // If there is no bidirectional info.
+ return false;
+ }
+
+ // Find the bidi line where the character is laid-out.
+
+ const BidirectionalLineInfoRun* const bidirectionalLineInfoBuffer = mBidirectionalLineInfo.Begin();
+
+ // Check first if the character is in the previously fetched line.
+
+ BidirectionalLineRunIndex bidiLineIndex = 0u;
+ CharacterIndex lastCharacterOfRightToLeftRun = 0u;
+ if( mBidirectionalLineIndex < numberOfBidirectionalLines )
+ {
+ const BidirectionalLineInfoRun& bidiLineRun = *( bidirectionalLineInfoBuffer + mBidirectionalLineIndex );
+
+ // Whether the character index is just after the last one. i.e The cursor position after the last character.
+ const bool isLastIndex = characterIndex == mText.Count();
+
+ const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
+ if( ( bidiLineRun.characterRun.characterIndex <= characterIndex ) &&
+ ( ( characterIndex < lastCharacterOfRunPlusOne ) || ( isLastIndex && ( characterIndex == lastCharacterOfRunPlusOne ) ) ) )
+ {
+ // The character is in the previously fetched bidi line.
+ return true;
+ }
+ else
{
- isRightToLeftParagraph = false;
- ++bidirectionalParagraphIndex;
- if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
+ // The character is not in the previously fetched line.
+
+ if( isLastIndex )
{
- bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
+ // The given index is one after the last character, so it's not in a bidi line.
+ // Check if it's just after the last bidi line.
+ const BidirectionalLineRunIndex lastBidiLineIndex = numberOfBidirectionalLines - 1u;
+ const BidirectionalLineInfoRun& bidiLineRun = *( bidirectionalLineInfoBuffer + lastBidiLineIndex );
+
+ if( characterIndex == bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters )
+ {
+ // The character is in the last bidi line.
+ mBidirectionalLineIndex = lastBidiLineIndex;
+ return true;
+ }
+ }
+
+ // Set the bidi line index from where to start the fetch.
+
+ if( characterIndex < bidiLineRun.characterRun.characterIndex )
+ {
+ // Start the fetch from the beginning.
+ bidiLineIndex = 0u;
}
else
{
- bidirectionalParagraph = NULL;
+ // Start the fetch from the next line.
+ bidiLineIndex = mBidirectionalLineIndex + 1u;
+ lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
}
}
}
-}
-CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
-{
- if( 0u == mVisualToLogicalMap.Count() )
+ // The character has not been found in the previously fetched bidi line.
+ for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLineInfoBuffer + bidiLineIndex,
+ endIt = mBidirectionalLineInfo.End();
+ it != endIt;
+ ++it, ++bidiLineIndex )
{
- // If there is no visual to logical info is because the whole text is left to right.
- // Return the identity.
- return visualCharacterIndex;
+ const BidirectionalLineInfoRun& bidiLineRun = *it;
+
+ if( ( lastCharacterOfRightToLeftRun < characterIndex ) && ( characterIndex < bidiLineRun.characterRun.characterIndex ) )
+ {
+ // The character is not inside a bidi line.
+ return false;
+ }
+
+ const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
+ lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
+ if( ( bidiLineRun.characterRun.characterIndex <= characterIndex ) &&
+ ( characterIndex < lastCharacterOfRunPlusOne ) )
+ {
+ // Bidi line found. Fetch the line.
+ mBidirectionalLineIndex = bidiLineIndex;
+ return true;
+ }
}
- return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
+ return false;
+}
+
+BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const
+{
+ return mBidirectionalLineIndex;
}
void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters )
}
LogicalModel::LogicalModel()
+: mBidirectionalLineIndex( 0u )
{
}