X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Fpublic-api%2Ftext%2Fshaper.cpp;h=376a1b7a00bc2e5f6fe724bb96f20838f47983ab;hp=3be21ab0976dfde95088cb7b582ff69bc5601635;hb=09e2475439f1d40c576df0fdc0bc9e26a9661758;hpb=2dd044328238768ae8b27a223cb7d0f5cda53513 diff --git a/dali-toolkit/public-api/text/shaper.cpp b/dali-toolkit/public-api/text/shaper.cpp index 3be21ab..376a1b7 100644 --- a/dali-toolkit/public-api/text/shaper.cpp +++ b/dali-toolkit/public-api/text/shaper.cpp @@ -18,6 +18,16 @@ // CLASS HEADER #include +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include + namespace Dali { @@ -27,6 +37,12 @@ namespace Toolkit namespace Text { +CharacterIndex min( CharacterIndex index0, + CharacterIndex index1 ) +{ + return ( index0 < index1 ) ? index0 : index1; +} + void ShapeText( const Vector& text, const Vector& lineBreakInfo, const Vector& scripts, @@ -35,6 +51,154 @@ void ShapeText( const Vector& text, Vector& characterIndices, Vector& charactersPerGlyph ) { + const Length numberOfCharacters = text.Count(); + + if( 0u == numberOfCharacters ) + { + // Nothing to do if there are no characters. + return; + } + +#ifdef DEBUG_ENABLED + const Length numberOfFontRuns = fonts.Count(); + const Length numberOfScriptRuns = scripts.Count(); +#endif + + DALI_ASSERT_DEBUG( ( 0u != numberOfFontRuns ) && + ( numberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) && + "Toolkit::Text::ShapeText. All characters must have a font set." ); + + DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) && + ( numberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) && + "Toolkit::Text::ShapeText. All characters must have a script set." ); + + // The text needs to be split in chunks of consecutive characters. + // Each chunk must contain characters with the same font id and script set. + // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk have to be created. + + TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get(); + + // To shape the text a font and an script is needed. + Vector::ConstIterator fontRunIt = fonts.Begin(); + Vector::ConstIterator scriptRunIt = scripts.Begin(); + + // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped. + CharacterIndex previousIndex = 0u; + + // The current font id and script used to shape the text. + FontId currentFontId = 0u; + Script currentScript = TextAbstraction::UNKNOWN; + + // Reserve some space to allocate the glyphs and the glyph to character map. + // There is no way to know the number of glyphs before shaping the text. + // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters. + + Length numberOfGlyphsReserved = static_cast( numberOfCharacters * 1.3f ); + glyphs.Resize( numberOfGlyphsReserved ); + charactersPerGlyph.Resize( numberOfGlyphsReserved ); + + // The actual number of glyphs. + Length totalNumberOfGlyphs = 0u; + + const Character* textBuffer = text.Begin(); + const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin(); + GlyphInfo* glyphsBuffer = glyphs.Begin(); + Length* charactersPerGlyphBuffer = charactersPerGlyph.Begin(); + + // Traverse the characters and shape the text. + for( previousIndex = 0; previousIndex < numberOfCharacters; ) + { + // Get the font id and the script. + const FontRun& fontRun = *fontRunIt; + const ScriptRun& scriptRun = *scriptRunIt; + + currentFontId = fontRun.fontId; + currentScript = scriptRun.script; + + // Get the min index to the last character of both runs. + CharacterIndex currentIndex = min( fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters, + scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ); + + // Check if there is a line must break. + bool mustBreak = false; + for( CharacterIndex index = previousIndex; index < currentIndex; ++index ) + { + mustBreak = TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ); + if( mustBreak ) + { + currentIndex = index; + break; + } + } + + // Check if the current index is a white space. Do not want to shape a \n. + // The last character is always a must-break even if it's not a \n. + Length numberOfCharactersToShape = currentIndex - previousIndex; + if( mustBreak && !IsWhiteSpace( *( textBuffer + currentIndex ) ) ) + { + ++numberOfCharactersToShape; + } + + // Shape the text for the current chunk. + const Length numberOfGlyphs = shaping.Shape( textBuffer + previousIndex, + numberOfCharactersToShape, + currentFontId, + currentScript ); + + const Length glyphIndex = totalNumberOfGlyphs; + totalNumberOfGlyphs += numberOfGlyphs; + + if( totalNumberOfGlyphs > numberOfGlyphsReserved ) + { + // Resize the vectors to get enough space. + numberOfGlyphsReserved = static_cast( totalNumberOfGlyphs * 1.3f ); + glyphs.Resize( numberOfGlyphsReserved ); + charactersPerGlyph.Resize( numberOfGlyphsReserved ); + + // Iterators are not valid anymore, set them again. + glyphsBuffer = glyphs.Begin(); + charactersPerGlyphBuffer = charactersPerGlyph.Begin(); + } + + // Retrieve the glyphs and the glyph to character conversion map. + shaping.GetGlyphs( glyphsBuffer + glyphIndex, + charactersPerGlyphBuffer + glyphIndex ); + + // Update the iterators to get the next font or script run. + if( currentIndex == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) + { + ++fontRunIt; + } + if( currentIndex == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) + { + ++scriptRunIt; + } + + // Update the previous index. Jumps the \n if needed. + previousIndex = mustBreak ? currentIndex + 1u : currentIndex; + } + + characterIndices.Reserve( totalNumberOfGlyphs ); + CharacterIndex characterIndex = 0u; + characterIndices.PushBack( characterIndex ); + for( Length index = 0u, length = totalNumberOfGlyphs - 1u; index < length; ++index ) + { + characterIndex += *( charactersPerGlyphBuffer + index ); + characterIndices.PushBack( characterIndex ); + } + + // Resize the vectors to set the right number of items. + glyphs.Resize( totalNumberOfGlyphs ); + // characterIndices.Resize( totalNumberOfGlyphs ); + charactersPerGlyph.Resize( totalNumberOfGlyphs ); +} + +void ShapeText( const LogicalModel& logicalModel, + VisualModel& visualModel, + CharacterIndex characterIndex, + Length numberOfCharactersToRemove, + Length numberOfCharactersToInsert ) +{ } } // namespace Text