X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Fmulti-language-support-impl.cpp;h=ec9167bc379c979217044363f8eefb72ce6e474f;hb=a9cd6af3e5040c890e57dd91b7639f11cad4c490;hp=f37bdc271f176909f899cf45d1ad70307776f262;hpb=4d763eb68b5aa2448dfc81d90fc5ce598c68c99f;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/text/multi-language-support-impl.cpp b/dali-toolkit/internal/text/multi-language-support-impl.cpp index f37bdc2..ec9167b 100644 --- a/dali-toolkit/internal/text/multi-language-support-impl.cpp +++ b/dali-toolkit/internal/text/multi-language-support-impl.cpp @@ -23,6 +23,9 @@ #include #include +// INTERNAL INCLUDES +#include + namespace Dali { @@ -44,132 +47,37 @@ namespace Text namespace Internal { -/** - * @brief Merges the font descriptions to retrieve the font Id for each character. - * - * @param[in] fontDescriptions The font descriptions. - * @param[out] fontIds The font id for each character. - * @param[in] defaultFontDescription The default font description. - * @param[in] defaultPointSize The default font size. - */ -void MergeFontDescriptions( const Vector& fontDescriptions, - Vector& fontIds, - const TextAbstraction::FontDescription& defaultFontDescription, - TextAbstraction::PointSize26Dot6 defaultPointSize ) -{ - // Get the handle to the font client. - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - - // Pointer to the font id buffer. - FontId* fontIdsBuffer = fontIds.Begin(); - - // Traverse all the characters. - const Length numberOfCharacters = fontIds.Count(); - for( CharacterIndex index = 0u; index < numberOfCharacters; ++index ) - { - // The default font description and font point size. - TextAbstraction::FontDescription fontDescription = defaultFontDescription; - TextAbstraction::PointSize26Dot6 fontSize = defaultPointSize; - bool defaultFont = true; - - // Traverse all the font descriptions. - for( Vector::ConstIterator it = fontDescriptions.Begin(), - endIt = fontDescriptions.End(); - it != endIt; - ++it ) - { - // Check whether the character's font is modified by the current font description. - const FontDescriptionRun& fontRun = *it; - if( ( index >= fontRun.characterRun.characterIndex ) && - ( index < fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) ) - { - if( fontRun.familyDefined ) - { - fontDescription.family = std::string( fontRun.familyName, fontRun.familyLength ); - defaultFont = false; - } - if( fontRun.weightDefined ) - { - fontDescription.weight = fontRun.weight; - defaultFont = false; - } - if( fontRun.widthDefined ) - { - fontDescription.width = fontRun.width; - defaultFont = false; - } - if( fontRun.slantDefined ) - { - fontDescription.slant = fontRun.slant; - defaultFont = false; - } - if( fontRun.sizeDefined ) - { - fontSize = fontRun.size; - defaultFont = false; - } - } - } - - // Get the font id if is not the default font. - if( !defaultFont ) - { - *( fontIdsBuffer + index ) = fontClient.GetFontId( fontDescription, fontSize ); - } - } -} - -/** - * @brief Retrieves the script Id from the script run for a given character's @p index. - * - * If the character's index exceeds the current script run it increases the iterator to get the next one. - * - * @param[in] index The character's index. - * @param[in,out] scriptRunIt Iterator to the current font run. - * @param[in] scriptRunEndIt Iterator to one after the last script run. - * - * @return The script. - */ -Script GetScript( Length index, - Vector::ConstIterator& scriptRunIt, - const Vector::ConstIterator& scriptRunEndIt ) +bool ValidateFontsPerScript::FindValidFont( FontId fontId ) const { - Script script = TextAbstraction::UNKNOWN; - - if( scriptRunIt != scriptRunEndIt ) + for( Vector::ConstIterator it = mValidFonts.Begin(), + endIt = mValidFonts.End(); + it != endIt; + ++it ) { - const ScriptRun& scriptRun = *scriptRunIt; - - if( ( index >= scriptRun.characterRun.characterIndex ) && - ( index < scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) ) - { - script = scriptRun.script; - } - - if( index + 1u == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) + if( fontId == *it ) { - // All the characters of the current run have been traversed. Get the next one for the next iteration. - ++scriptRunIt; + return true; } } - return script; + return false; } -bool ValidateFontsPerScript::FindValidFont( FontId fontId ) const +FontId DefaultFonts::FindFont( TextAbstraction::FontClient& fontClient, PointSize26Dot6 size ) const { - for( Vector::ConstIterator it = mValidFonts.Begin(), - endIt = mValidFonts.End(); + for( Vector::ConstIterator it = mFonts.Begin(), + endIt = mFonts.End(); it != endIt; ++it ) { - if( fontId == *it ) + const FontId fontId = *it; + if( size == fontClient.GetPointSize( fontId ) ) { - return true; + return fontId; } } - return false; + return 0u; } MultilanguageSupport::MultilanguageSupport() @@ -178,7 +86,7 @@ MultilanguageSupport::MultilanguageSupport() { // Initializes the default font cache to zero (invalid font). // Reserves space to cache the default fonts and access them with the script as an index. - mDefaultFontPerScriptCache.Resize( TextAbstraction::UNKNOWN, 0u ); + mDefaultFontPerScriptCache.Resize( TextAbstraction::UNKNOWN, NULL ); // Initializes the valid fonts cache to NULL (no valid fonts). // Reserves space to cache the valid fonts and access them with the script as an index. @@ -187,8 +95,16 @@ MultilanguageSupport::MultilanguageSupport() MultilanguageSupport::~MultilanguageSupport() { - // Destroy the valid fonts per script cache. + // Destroy the default font per script cache. + for( Vector::Iterator it = mDefaultFontPerScriptCache.Begin(), + endIt = mDefaultFontPerScriptCache.End(); + it != endIt; + ++it ) + { + delete *it; + } + // Destroy the valid fonts per script cache. for( Vector::Iterator it = mValidFontsPerScriptCache.Begin(), endIt = mValidFontsPerScriptCache.End(); it != endIt; @@ -224,24 +140,42 @@ Text::MultilanguageSupport MultilanguageSupport::Get() } void MultilanguageSupport::SetScripts( const Vector& text, + CharacterIndex startIndex, + Length numberOfCharacters, Vector& scripts ) { - const Length numberOfCharacters = text.Count(); - if( 0u == numberOfCharacters ) { // Nothing to do if there are no characters. return; } + // Find the first index where to insert the script. + ScriptRunIndex scriptIndex = 0u; + if( 0u != startIndex ) + { + for( Vector::ConstIterator it = scripts.Begin(), + endIt = scripts.End(); + it != endIt; + ++it, ++scriptIndex ) + { + const ScriptRun& run = *it; + if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters ) + { + // Run found. + break; + } + } + } + // Stores the current script run. ScriptRun currentScriptRun; - currentScriptRun.characterRun.characterIndex = 0u; + currentScriptRun.characterRun.characterIndex = startIndex; currentScriptRun.characterRun.numberOfCharacters = 0u; currentScriptRun.script = TextAbstraction::UNKNOWN; // Reserve some space to reduce the number of reallocations. - scripts.Reserve( numberOfCharacters << 2u ); + scripts.Reserve( text.Count() << 2u ); // Whether the first valid script needs to be set. bool isFirstScriptToBeSet = true; @@ -256,7 +190,8 @@ void MultilanguageSupport::SetScripts( const Vector& text, const Character* const textBuffer = text.Begin(); // Traverse all characters and set the scripts. - for( Length index = 0u; index < numberOfCharacters; ++index ) + const Length lastCharacter = startIndex + numberOfCharacters; + for( Length index = startIndex; index < lastCharacter; ++index ) { Character character = *( textBuffer + index ); @@ -272,7 +207,7 @@ void MultilanguageSupport::SetScripts( const Vector& text, // script of the first character of the paragraph with a defined script. // Skip those characters valid for many scripts like white spaces or '\n'. - bool endOfText = index == numberOfCharacters; + bool endOfText = index == lastCharacter; while( !endOfText && ( TextAbstraction::COMMON == script ) ) { @@ -287,17 +222,27 @@ void MultilanguageSupport::SetScripts( const Vector& text, // the same direction than the first script of the paragraph. isFirstScriptToBeSet = true; - // Characters common to all scripts at the end of the paragraph are added to the last script (if the last one is not unknown). - if( TextAbstraction::UNKNOWN != currentScriptRun.script ) + // Characters common to all scripts at the end of the paragraph are added to the last script. + currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; + + // Store the script run. + if( TextAbstraction::UNKNOWN == currentScriptRun.script ) { - currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; - numberOfAllScriptCharacters = 0u; + currentScriptRun.script = TextAbstraction::LATIN; } - } + scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun ); + ++scriptIndex; + + // Initialize the new one. + currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters; + currentScriptRun.characterRun.numberOfCharacters = 0u; + currentScriptRun.script = TextAbstraction::UNKNOWN; + numberOfAllScriptCharacters = 0u; + } // Get the next character. ++index; - endOfText = index == numberOfCharacters; + endOfText = index == lastCharacter; if( !endOfText ) { character = *( textBuffer + index ); @@ -347,7 +292,8 @@ void MultilanguageSupport::SetScripts( const Vector& text, if( 0u != currentScriptRun.characterRun.numberOfCharacters ) { // Store the script run. - scripts.PushBack( currentScriptRun ); + scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun ); + ++scriptIndex; } // Initialize the new one. @@ -373,29 +319,46 @@ void MultilanguageSupport::SetScripts( const Vector& text, // Add remaining characters into the last script. currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; - DALI_ASSERT_DEBUG( ( 0u != currentScriptRun.characterRun.numberOfCharacters ) && "MultilanguageSupport::SetScripts() Trying to insert a script run with zero characters." ); - - if( TextAbstraction::UNKNOWN == currentScriptRun.script ) + if( 0u != currentScriptRun.characterRun.numberOfCharacters ) { - // There are only white spaces in the last script. Set the latin script. - currentScriptRun.script = TextAbstraction::LATIN; + if( TextAbstraction::UNKNOWN == currentScriptRun.script ) + { + // There are only white spaces in the last script. Set the latin script. + currentScriptRun.script = TextAbstraction::LATIN; + } + + // Store the last run. + scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun ); + ++scriptIndex; } - // Store the last run. - scripts.PushBack( currentScriptRun ); + if( scriptIndex < scripts.Count() ) + { + // Update the indices of the next script runs. + const ScriptRun& run = *( scripts.Begin() + scriptIndex - 1u ); + CharacterIndex nextCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters; + + for( Vector::Iterator it = scripts.Begin() + scriptIndex, + endIt = scripts.End(); + it != endIt; + ++it ) + { + ScriptRun& run = *it; + run.characterRun.characterIndex = nextCharacterIndex; + nextCharacterIndex += run.characterRun.numberOfCharacters; + } + } } void MultilanguageSupport::ValidateFonts( const Vector& text, const Vector& scripts, const Vector& fontDescriptions, FontId defaultFontId, + CharacterIndex startIndex, + Length numberOfCharacters, Vector& fonts ) { - // Clear any previously validated font. - fonts.Clear(); - DALI_LOG_INFO( gLogFilter, Debug::General, "-->MultilanguageSupport::ValidateFonts\n" ); - const Length numberOfCharacters = text.Count(); if( 0u == numberOfCharacters ) { @@ -404,10 +367,28 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, return; } + // Find the first index where to insert the font run. + FontRunIndex fontIndex = 0u; + if( 0u != startIndex ) + { + for( Vector::ConstIterator it = fonts.Begin(), + endIt = fonts.End(); + it != endIt; + ++it, ++fontIndex ) + { + const FontRun& run = *it; + if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters ) + { + // Run found. + break; + } + } + } + // Traverse the characters and validate/set the fonts. // Get the caches. - FontId* defaultFontPerScriptCacheBuffer = mDefaultFontPerScriptCache.Begin(); + DefaultFonts** defaultFontPerScriptCacheBuffer = mDefaultFontPerScriptCache.Begin(); ValidateFontsPerScript** validFontsPerScriptCacheBuffer = mValidFontsPerScriptCache.Begin(); // Stores the validated font runs. @@ -415,7 +396,7 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // Initializes a validated font run. FontRun currentFontRun; - currentFontRun.characterRun.characterIndex = 0u; + currentFontRun.characterRun.characterIndex = startIndex; currentFontRun.characterRun.numberOfCharacters = 0u; currentFontRun.fontId = 0u; @@ -437,26 +418,40 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, MergeFontDescriptions( fontDescriptions, fontIds, defaultFontDescription, - defaultPointSize ); + defaultPointSize, + startIndex, + numberOfCharacters ); const Character* const textBuffer = text.Begin(); const FontId* const fontIdsBuffer = fontIds.Begin(); Vector::ConstIterator scriptRunIt = scripts.Begin(); Vector::ConstIterator scriptRunEndIt = scripts.End(); + bool isNewParagraphCharacter = false; + + PointSize26Dot6 currentPointSize = defaultPointSize; + FontId currentFontId = 0u; - for( Length index = 0u; index < numberOfCharacters; ++index ) + CharacterIndex lastCharacter = startIndex + numberOfCharacters; + for( Length index = startIndex; index < lastCharacter; ++index ) { // Get the character. const Character character = *( textBuffer + index ); // Get the font for the character. - FontId fontId = *( fontIdsBuffer + index ); + FontId fontId = *( fontIdsBuffer + index - startIndex ); // Get the script for the character. Script script = GetScript( index, scriptRunIt, scriptRunEndIt ); + // Get the current point size. + if( currentFontId != fontId ) + { + currentPointSize = fontClient.GetPointSize( fontId ); + currentFontId = fontId; + } + #ifdef DEBUG_ENABLED { Dali::TextAbstraction::FontDescription description; @@ -471,12 +466,6 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, } #endif - if( TextAbstraction::UNKNOWN == script ) - { - DALI_LOG_WARNING( "MultilanguageSupport::ValidateFonts. Unknown script!" ); - script = TextAbstraction::LATIN; - } - // Whether the font being validated is a default one not set by the user. FontId preferredFont = fontId; @@ -484,8 +473,15 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // Check first in the caches. + DefaultFonts* defaultFonts = *( defaultFontPerScriptCacheBuffer + script ); + FontId cachedDefaultFontId = 0u; + if( NULL != defaultFonts ) + { + cachedDefaultFontId = defaultFonts->FindFont( fontClient, currentPointSize ); + } + // The user may have set the default font. Check it. Otherwise check in the valid fonts cache. - if( fontId != *( defaultFontPerScriptCacheBuffer + script ) ) + if( fontId != cachedDefaultFontId ) { // Check in the valid fonts cache. ValidateFontsPerScript* validateFontsPerScript = *( validFontsPerScriptCacheBuffer + script ); @@ -554,7 +550,7 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, if( 0u == fontId ) { // The character has no font assigned. Get a default one from the cache - fontId = *( defaultFontPerScriptCacheBuffer + script ); + fontId = cachedDefaultFontId; // If the cache has not a default font, get one from the font client. if( 0u == fontId ) @@ -563,20 +559,31 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, bool preferColor = ( TextAbstraction::EMOJI == script ); // Find a fallback-font. - fontId = fontClient.FindFallbackFont( preferredFont, character, defaultPointSize, preferColor ); + fontId = fontClient.FindFallbackFont( preferredFont, character, currentPointSize, preferColor ); // If the system does not support a suitable font, fallback to Latin + DefaultFonts* latinDefaults = NULL; if( 0u == fontId ) { - fontId = *( defaultFontPerScriptCacheBuffer + TextAbstraction::LATIN ); + latinDefaults = *( defaultFontPerScriptCacheBuffer + TextAbstraction::LATIN ); + if( NULL != latinDefaults ) + { + fontId = latinDefaults->FindFont( fontClient, currentPointSize ); + } } + if( 0u == fontId ) { - fontId = fontClient.FindDefaultFont( UTF32_A, defaultPointSize ); + fontId = fontClient.FindDefaultFont( UTF32_A, currentPointSize ); } // Cache the font. - *( defaultFontPerScriptCacheBuffer + script ) = fontId; + if( NULL == latinDefaults ) + { + latinDefaults = new DefaultFonts(); + *( defaultFontPerScriptCacheBuffer + script ) = latinDefaults; + } + latinDefaults->mFonts.PushBack( fontId ); } } @@ -594,15 +601,16 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, #endif // The font is now validated. - - if( fontId != currentFontRun.fontId ) + if( ( fontId != currentFontRun.fontId ) || + isNewParagraphCharacter ) { // Current run needs to be stored and a new one initialized. if( 0u != currentFontRun.characterRun.numberOfCharacters ) { // Store the font run. - fonts.PushBack( currentFontRun ); + fonts.Insert( fonts.Begin() + fontIndex, currentFontRun ); + ++fontIndex; } // Initialize the new one. @@ -613,13 +621,36 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // Add one more character to the run. ++currentFontRun.characterRun.numberOfCharacters; + + // Whether the current character is a new paragraph character. + isNewParagraphCharacter = TextAbstraction::IsNewParagraph( character ); } if( 0u != currentFontRun.characterRun.numberOfCharacters ) { // Store the last run. - fonts.PushBack( currentFontRun ); + fonts.Insert( fonts.Begin() + fontIndex, currentFontRun ); + ++fontIndex; } + + if( fontIndex < fonts.Count() ) + { + // Update the indices of the next font runs. + const FontRun& run = *( fonts.Begin() + fontIndex - 1u ); + CharacterIndex nextCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters; + + for( Vector::Iterator it = fonts.Begin() + fontIndex, + endIt = fonts.End(); + it != endIt; + ++it ) + { + FontRun& run = *it; + + run.characterRun.characterIndex = nextCharacterIndex; + nextCharacterIndex += run.characterRun.numberOfCharacters; + } + } + DALI_LOG_INFO( gLogFilter, Debug::General, "<--MultilanguageSupport::ValidateFonts\n" ); }