-LineIndex Controller::Impl::GetClosestLine( float y ) const
-{
- float totalHeight = 0.f;
- LineIndex lineIndex = 0u;
-
- const Vector<LineRun>& lines = mVisualModel->mLines;
- for( LineIndex endLine = lines.Count();
- lineIndex < endLine;
- ++lineIndex )
- {
- const LineRun& lineRun = lines[lineIndex];
- totalHeight += lineRun.ascender + -lineRun.descender;
- if( y < totalHeight )
- {
- return lineIndex;
- }
- }
-
- if( lineIndex == 0 )
- {
- return 0;
- }
-
- return lineIndex-1;
-}
-
-void Controller::Impl::FindSelectionIndices( float visualX, float visualY, CharacterIndex& startIndex, CharacterIndex& endIndex )
-{
- CharacterIndex hitCharacter = GetClosestCursorIndex( visualX, visualY );
- DALI_ASSERT_DEBUG( hitCharacter <= mLogicalModel->mText.Count() && "GetClosestCursorIndex returned out of bounds index" );
-
- if( mLogicalModel->mText.Count() == 0 )
- {
- return; // if model empty
- }
-
- if( hitCharacter >= mLogicalModel->mText.Count() )
- {
- // Closest hit character is the last character.
- if( hitCharacter == mLogicalModel->mText.Count() )
- {
- hitCharacter--; //Hit character index set to last character in logical model
- }
- else
- {
- // hitCharacter is out of bounds
- return;
- }
- }
-
- startIndex = hitCharacter;
- endIndex = hitCharacter;
- bool isHitCharacterWhitespace = TextAbstraction::IsWhiteSpace( mLogicalModel->mText[hitCharacter] );
-
- // Find the start and end of the text
- for( startIndex = hitCharacter; startIndex > 0; --startIndex )
- {
- if( isHitCharacterWhitespace != TextAbstraction::IsWhiteSpace( mLogicalModel->mText[ startIndex-1 ] ) )
- {
- break;
- }
- }
- const CharacterIndex pastTheEnd = mLogicalModel->mText.Count();
- for( endIndex = hitCharacter + 1u; endIndex < pastTheEnd; ++endIndex )
- {
- if( isHitCharacterWhitespace != TextAbstraction::IsWhiteSpace( mLogicalModel->mText[ endIndex ] ) )
- {
- break;
- }
- }
-}
-
-CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
- float visualY )
-{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetClosestCursorIndex %p closest visualX %f visualY %f\n", this, visualX, visualY );
-
- if( NULL == mEventData )
- {
- // Nothing to do if there is no text input.
- return 0u;
- }
-
- CharacterIndex logicalIndex = 0u;
-
- const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
- const Length numberOfLines = mVisualModel->mLines.Count();
- if( ( 0 == numberOfGlyphs ) ||
- ( 0 == numberOfLines ) )
- {
- return logicalIndex;
- }
-
- // Find which line is closest
- const LineIndex lineIndex = GetClosestLine( visualY );
- const LineRun& line = mVisualModel->mLines[lineIndex];
-
- // Get the positions of the glyphs.
- const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
- const Vector2* const positionsBuffer = positions.Begin();
-
- // Get the visual to logical conversion tables.
- const CharacterIndex* const visualToLogicalBuffer = ( 0u != mLogicalModel->mVisualToLogicalMap.Count() ) ? mLogicalModel->mVisualToLogicalMap.Begin() : NULL;
- const CharacterIndex* const visualToLogicalCursorBuffer = mLogicalModel->mVisualToLogicalCursorMap.Begin();
-
- // Get the character to glyph conversion table.
- const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
-
- // Get the glyphs per character table.
- const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
-
- // Get the glyph's info buffer.
- const GlyphInfo* const glyphInfoBuffer = mVisualModel->mGlyphs.Begin();
-
- // If the vector is void, there is no right to left characters.
- const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
-
- const CharacterIndex startCharacter = line.characterRun.characterIndex;
- const CharacterIndex endCharacter = line.characterRun.characterIndex + line.characterRun.numberOfCharacters;
- DALI_ASSERT_DEBUG( endCharacter <= mLogicalModel->mText.Count() && "Invalid line info" );
-
- // Whether there is a hit on a glyph.
- bool matched = false;
-
- // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
- CharacterIndex visualIndex = startCharacter;
- Length numberOfCharacters = 0u;
- for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
- {
- // The character in logical order.
- const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
-
- // Get the script of the character.
- const Script script = mLogicalModel->GetScript( characterLogicalOrderIndex );
-
- // The number of glyphs for that character
- const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
- ++numberOfCharacters;
-
-
- if( 0u != numberOfGlyphs )
- {
- // Get the first character/glyph of the group of glyphs.
- const CharacterIndex firstVisualCharacterIndex = 1u + visualIndex - numberOfCharacters;
- const CharacterIndex firstLogicalCharacterIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + firstVisualCharacterIndex ) : firstVisualCharacterIndex;
- const GlyphIndex firstLogicalGlyphIndex = *( charactersToGlyphBuffer + firstLogicalCharacterIndex );
-
- // Get the metrics for the group of glyphs.
- GlyphMetrics glyphMetrics;
- GetGlyphsMetrics( firstLogicalGlyphIndex,
- numberOfGlyphs,
- glyphMetrics,
- glyphInfoBuffer,
- mMetrics );
-
- // Get the position of the first glyph.
- const Vector2& position = *( positionsBuffer + firstLogicalGlyphIndex );
-
- // Whether the glyph can be split, like Latin ligatures fi, ff or Arabic ï»».
- const bool isInterglyphIndex = ( numberOfCharacters > numberOfGlyphs ) && HasLigatureMustBreak( script );
- const Length numberOfBlocks = isInterglyphIndex ? numberOfCharacters : 1u;
- const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfBlocks );
-
- GlyphIndex index = 0u;
- for( ; !matched && ( index < numberOfBlocks ); ++index )
- {
- // Find the mid-point of the area containing the glyph
- const float glyphCenter = -glyphMetrics.xBearing + position.x + ( static_cast<float>( index ) + 0.5f ) * glyphAdvance;
-
- if( visualX < glyphCenter )
- {
- matched = true;
- break;
- }
- }
-
- if( matched )
- {
- visualIndex = firstVisualCharacterIndex + index;
- break;
- }
-
- numberOfCharacters = 0u;
- }
-
- }
-
-
- // Return the logical position of the cursor in characters.
-
- if( !matched )
- {
- visualIndex = endCharacter;
- }
-
- logicalIndex = hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p closest visualIndex %d logicalIndex %d\n", this, visualIndex, logicalIndex );
-
- DALI_ASSERT_DEBUG( ( logicalIndex <= mLogicalModel->mText.Count() && logicalIndex >= 0 ) && "GetClosestCursorIndex - Out of bounds index" );
-
- return logicalIndex;
-}
-