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<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<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()
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
+ const Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
memcpy( glyphs, modelGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
}
CharacterIndex characterIndex,
Length numberOfCharacters ) const
{
- Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
+ const Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
memcpy( characterToGlyphMap, modelCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
}
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
+ const Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
memcpy( charactersPerGlyph, modelCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
}
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
+ const Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
memcpy( glyphToCharacter, modelGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
}
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
{
- Vector<Vector2> modelPositions = mImpl->mGlyphPositions;
+ const Vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
memcpy( glyphPositions, modelPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
}
void VisualModel::SetLines( const LineRun* const lines,
Length numberOfLines )
{
+ Vector<LineRun>& modelLines = mImpl->mLines;
+ GetLineCache& lineCache = mImpl->mGetLineCache;
+
+ 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 cound 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::SetNaturalSize( const Vector2& size )