// EXTERNAL INCLUDES
#include <memory.h>
-
-// INTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/line-run.h>
namespace Dali
namespace Text
{
+/**
+ * @brief caches some temporary values of the GetNumberOfLines( glyphIndex, numberOfGlyphs ) operation
+ * as they are going to be used in the GetLinesOfGlyphRange() call.
+ */
+struct GetLineCache
+{
+ GlyphIndex glyphIndex; ///< The glyph index.
+ Length numberOfGlyphs; ///< The number of glyphs.
+ Length firstLine; ///< Index to the first line.
+ Length numberOfLines; ///< The number of lines.
+};
+
struct VisualModel::Impl
{
Vector<GlyphInfo> mGlyphs; ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
Vector<CharacterIndex> mGlyphsToCharacters; ///< For each glyph, the index of the first character.
Vector<GlyphIndex> mCharactersToGlyph; ///< For each character, the index of the first glyph.
Vector<Length> mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph.
+ Vector<Length> mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
Vector<Vector2> mGlyphPositions; ///< For each glyph, the position.
+ Vector<LineRun> mLines; ///< The laid out lines.
+
+ Size mNaturalSize; ///< Size of the text with no line wrapping.
+ Size mActualSize; ///< Size of the laid-out text considering the layout properties set.
- Size mNaturalSize;
- Size mActualSize;
+ GetLineCache mGetLineCache; ///< Caches the GetNumberOfLines( glyphIndex, numberOfGlyphs ) operation.
};
VisualModelPtr VisualModel::New()
Length numberOfGlyphs )
{
Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
- modelGlyphs.Resize( numberOfGlyphs );
- memcpy( modelGlyphs.Begin(), glyphs, numberOfGlyphs * sizeof( GlyphInfo ) );
-
Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
- modelGlyphsToCharacters.Resize( numberOfGlyphs );
- memcpy( modelGlyphsToCharacters.Begin(), characterIndices, numberOfGlyphs * sizeof( CharacterIndex ) );
-
- Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
- modelCharactersPerGlyph.Resize( numberOfGlyphs );
- memcpy( modelCharactersPerGlyph.Begin(), charactersPerGlyph, numberOfGlyphs * sizeof( Length ) );
-
- // Build the characters to glyph conversion table.
Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
+ Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
+ Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
- // 1) Reserve some space for the characters to avoid reallocations.
- modelCharactersToGlyph.Reserve( static_cast<Length> ( static_cast<float>( numberOfGlyphs ) * 1.3f ) );
-
- // 2) Traverse the glyphs and set the glyph indices.
- GlyphIndex glyphIndex = 0u;
- Length totalNumberOfCharacters = 0u;
- for( Vector<Length>::ConstIterator it = modelCharactersPerGlyph.Begin(),
- endIt = modelCharactersPerGlyph.End();
- it != endIt;
- ++it, ++glyphIndex )
+ if( 0u == numberOfGlyphs )
{
- const Length numberOfCharacters = *it;
+ modelGlyphs.Clear();
+ modelGlyphsToCharacters.Clear();
+ modelCharactersToGlyph.Clear();
+ modelCharactersPerGlyph.Clear();
+ modelGlyphsPerCharacter.Clear();
+ }
+ else
+ {
+ if( NULL != glyphs )
+ {
+ modelGlyphs.Resize( numberOfGlyphs );
+ memcpy( modelGlyphs.Begin(), glyphs, numberOfGlyphs * sizeof( GlyphInfo ) );
+ }
- for( Length index = 0u; index < numberOfCharacters; ++index, ++totalNumberOfCharacters )
+ if( NULL != characterIndices )
{
- modelCharactersToGlyph.PushBack( glyphIndex );
+ modelGlyphsToCharacters.Resize( numberOfGlyphs );
+ memcpy( modelGlyphsToCharacters.Begin(), characterIndices, numberOfGlyphs * sizeof( CharacterIndex ) );
+ }
+
+ if( NULL != charactersPerGlyph )
+ {
+ modelCharactersPerGlyph.Resize( numberOfGlyphs );
+ memcpy( modelCharactersPerGlyph.Begin(), charactersPerGlyph, numberOfGlyphs * sizeof( Length ) );
+
+ // Build the characters to glyph conversion table.
+
+ // 1) Reserve some space for the characters to avoid reallocations.
+ const Length numberOfCharacters = static_cast<Length> ( static_cast<float>( numberOfGlyphs ) * 1.3f );
+ modelCharactersToGlyph.Reserve( numberOfCharacters );
+ modelGlyphsPerCharacter.Reserve( numberOfCharacters );
+
+ // 2) Traverse the glyphs and set the glyph indices and the glyphs per character.
+
+ // The number of 'characters per glyph' equal to zero.
+ Length zeroCharactersPerGlyph = 0u;
+
+ // Index to the glyph.
+ GlyphIndex glyphIndex = 0u;
+ for( Vector<Length>::ConstIterator it = modelCharactersPerGlyph.Begin(),
+ endIt = modelCharactersPerGlyph.End();
+ it != endIt;
+ ++it, ++glyphIndex )
+ {
+ const Length numberOfCharacters = *it;
+
+ // Set the glyph indices.
+ for( Length index = 0u; index < numberOfCharacters; ++index )
+ {
+ modelCharactersToGlyph.PushBack( glyphIndex );
+ }
+
+ // Set the glyphs per character.
+ if( 0u == numberOfCharacters )
+ {
+ ++zeroCharactersPerGlyph;
+ }
+ else
+ {
+ const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharacters - 1u );
+ for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex )
+ {
+ modelGlyphsPerCharacter.PushBack( 0u );
+ }
+
+ modelGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph );
+
+ zeroCharactersPerGlyph = 0u;
+ }
+ }
}
}
}
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
+ const Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
memcpy( glyphs, modelGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
}
return mImpl->mGlyphs[glyphIndex];
}
+void VisualModel::ReplaceGlyphs( GlyphIndex glyphIndex,
+ Length numberOfGlyphsToRemove,
+ const GlyphInfo* const glyphs,
+ const Length* const numberOfCharacters,
+ Length numberOfGlyphsToInsert )
+{
+}
+
CharacterIndex VisualModel::GetCharacterIndex( GlyphIndex glyphIndex ) const
{
return mImpl->mGlyphsToCharacters[glyphIndex];
CharacterIndex characterIndex,
Length numberOfCharacters ) const
{
- Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
+ const Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
memcpy( characterToGlyphMap, modelCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
}
+void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
+ GlyphIndex glyphIndex,
+ Length numberOfGlyphs ) const
+{
+ const Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
+ memcpy( glyphToCharacter, modelGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
+}
+
void VisualModel::GetCharactersPerGlyphMap( Length* charactersPerGlyph,
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
+ const Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
memcpy( charactersPerGlyph, modelCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
}
-void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
- GlyphIndex glyphIndex,
- Length numberOfGlyphs ) const
+void VisualModel::GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
+ CharacterIndex characterIndex,
+ Length numberOfCharacters ) const
{
- Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
- memcpy( glyphToCharacter, modelGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
+ const Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
+ memcpy( glyphsPerCharacter, modelGlyphsPerCharacter.Begin() + characterIndex, numberOfCharacters * sizeof( Length ) );
}
void VisualModel::SetGlyphPositions( const Vector2* glyphPositions,
Length numberOfGlyphs )
{
Vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
- modelPositions.Resize( numberOfGlyphs );
- memcpy( modelPositions.Begin(), glyphPositions, numberOfGlyphs * sizeof( Vector2 ) );
+ if( 0u == numberOfGlyphs )
+ {
+ modelPositions.Clear();
+ }
+ else
+ {
+ modelPositions.Resize( numberOfGlyphs );
+ memcpy( modelPositions.Begin(), glyphPositions, numberOfGlyphs * sizeof( Vector2 ) );
+ }
+}
+
+Length VisualModel::GetNumberOfGlyphPositions() const
+{
+ return mImpl->mGlyphPositions.Count();
}
void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- Vector<Vector2> modelPositions = mImpl->mGlyphPositions;
+ const Vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
memcpy( glyphPositions, modelPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
}
return *( mImpl->mGlyphPositions.Begin() + glyphIndex );
}
+void VisualModel::ReplaceGlyphPositions( GlyphIndex glyphIndex,
+ Length numberOfGlyphsToRemove,
+ const Vector2* const positions,
+ Length numberOfGlyphsToInsert )
+{
+}
+
void VisualModel::SetLines( const LineRun* const lines,
Length numberOfLines )
{
+ Vector<LineRun>& modelLines = mImpl->mLines;
+ GetLineCache& lineCache = mImpl->mGetLineCache;
+
+ if( 0u == numberOfLines )
+ {
+ modelLines.Clear();
+ }
+ else
+ {
+ modelLines.Resize( numberOfLines );
+ memcpy( modelLines.Begin(), lines, numberOfLines * sizeof( LineRun ) );
+ }
+
+ // Clear the get line cache.
+ lineCache.glyphIndex = 0u;
+ lineCache.numberOfGlyphs = 0u;
+ lineCache.firstLine = 0u;
+ lineCache.numberOfLines = 0u;
}
Length VisualModel::GetNumberOfLines() const
{
- return 0u;
+ return mImpl->mLines.Count();
}
void VisualModel::GetLines( LineRun* lines,
LineIndex lineIndex,
Length numberOfLines ) const
{
+ const Vector<LineRun>& modelLines = mImpl->mLines;
+ memcpy( lines, modelLines.Begin() + lineIndex, numberOfLines * sizeof( LineRun ) );
}
Length VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- return 0u;
+ // If is likely the user query consecutively for the number of lines with the same
+ // glyph index and number of glyphs, use the cache could be considered.
+ GetLineCache& lineCache = mImpl->mGetLineCache;
+
+ // Cache the glyph index and number of glyphs to be used in the GetLinesOfGlyphRange().
+ lineCache.glyphIndex = glyphIndex;
+ lineCache.numberOfGlyphs = numberOfGlyphs;
+
+ // Check first if the query is for the total number of glyphs.
+ const Length totalNumberOfGlyphs = mImpl->mGlyphs.Count();
+
+ if( ( 0u == glyphIndex ) &&
+ ( totalNumberOfGlyphs == numberOfGlyphs ) )
+ {
+ lineCache.firstLine = 0u;
+ lineCache.numberOfLines = mImpl->mLines.Count();
+
+ return lineCache.numberOfLines;
+ }
+
+ // Initialize the number of lines and the first line.
+ lineCache.numberOfLines = 0u;
+ lineCache.firstLine = 0u;
+ bool firstLineFound = false;
+
+ const Vector<LineRun>& modelLines = mImpl->mLines;
+ const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
+
+ // Traverse the lines and count those lines within the range of glyphs.
+ for( Vector<LineRun>::ConstIterator it = modelLines.Begin(),
+ endIt = modelLines.End();
+ it != endIt;
+ ++it )
+ {
+ const LineRun& line = *it;
+
+ if( ( line.glyphIndex + line.numberOfGlyphs > glyphIndex ) &&
+ ( lastGlyphIndex > line.glyphIndex ) )
+ {
+ firstLineFound = true;
+ ++lineCache.numberOfLines;
+ }
+ else if( lastGlyphIndex <= line.glyphIndex )
+ {
+ // nothing else to do.
+ break;
+ }
+
+ if( !firstLineFound )
+ {
+ ++lineCache.firstLine;
+ }
+ }
+
+ return lineCache.numberOfLines;
}
void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
+ const Vector<LineRun>& modelLines = mImpl->mLines;
+ GetLineCache& lineCache = mImpl->mGetLineCache;
+
+ if( ( glyphIndex != lineCache.glyphIndex ) ||
+ ( numberOfGlyphs != lineCache.numberOfGlyphs ) )
+ {
+ GetNumberOfLines( glyphIndex,
+ numberOfGlyphs );
+ }
+
+ memcpy( lines, modelLines.Begin() + lineCache.firstLine, lineCache.numberOfLines * sizeof( LineRun ) );
+}
+
+void VisualModel::ReplaceLines( GlyphIndex glyphIndex,
+ Length numberOfGlyphsToRemove,
+ const LineRun* const lines,
+ Length numberOfGlyphsToInsert )
+{
}
void VisualModel::SetNaturalSize( const Vector2& size )