X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Fmulti-language-support-impl.cpp;h=4b6eee2e26566edd9cae0c2e0295edaf9e890f28;hp=8b491b064942a653eff2a008a625078a05aff78e;hb=b85254b482e88b8f05b66e3656a1a29a7a7ea5fa;hpb=b5eca237428be8e01adaa98457b3cef3695d860d diff --git a/dali-toolkit/internal/text/multi-language-support-impl.cpp b/dali-toolkit/internal/text/multi-language-support-impl.cpp old mode 100644 new mode 100755 index 8b491b0..4b6eee2 --- a/dali-toolkit/internal/text/multi-language-support-impl.cpp +++ b/dali-toolkit/internal/text/multi-language-support-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,34 +63,49 @@ bool ValidateFontsPerScript::IsValidFont( FontId fontId ) const return false; } -FontId DefaultFonts::FindFont( TextAbstraction::FontClient& fontClient, PointSize26Dot6 size ) const +FontId DefaultFonts::FindFont( TextAbstraction::FontClient& fontClient, + const TextAbstraction::FontDescription& description, + PointSize26Dot6 size ) const { - for( Vector::ConstIterator it = mFonts.Begin(), - endIt = mFonts.End(); + for( std::vector::const_iterator it = mFonts.begin(), + endIt = mFonts.end(); it != endIt; ++it ) { - const FontId fontId = *it; - if( size == fontClient.GetPointSize( fontId ) ) + const CacheItem& item = *it; + + if( ( ( TextAbstraction::FontWeight::NONE == description.weight ) || ( description.weight == item.description.weight ) ) && + ( ( TextAbstraction::FontWidth::NONE == description.width ) || ( description.width == item.description.width ) ) && + ( ( TextAbstraction::FontSlant::NONE == description.slant ) || ( description.slant == item.description.slant ) ) && + ( size == fontClient.GetPointSize( item.fontId ) ) && + ( description.family.empty() || ( description.family == item.description.family ) ) ) { - return fontId; + return item.fontId; } } return 0u; } +void DefaultFonts::Cache( const TextAbstraction::FontDescription& description, FontId fontId ) +{ + CacheItem item; + item.description = description; + item.fontId = fontId; + mFonts.push_back( item ); +} + MultilanguageSupport::MultilanguageSupport() : mDefaultFontPerScriptCache(), mValidFontsPerScriptCache() { // 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, NULL ); + mDefaultFontPerScriptCache.Resize( TextAbstraction::UNKNOWN + 1, 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. - mValidFontsPerScriptCache.Resize( TextAbstraction::UNKNOWN, NULL ); + mValidFontsPerScriptCache.Resize( TextAbstraction::UNKNOWN + 1, NULL ); } MultilanguageSupport::~MultilanguageSupport() @@ -239,10 +254,6 @@ void MultilanguageSupport::SetScripts( const Vector& text, currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; // Store the script run. - if( TextAbstraction::UNKNOWN == currentScriptRun.script ) - { - currentScriptRun.script = TextAbstraction::LATIN; - } scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun ); ++scriptIndex; @@ -305,7 +316,6 @@ void MultilanguageSupport::SetScripts( const Vector& text, else if( ( TextAbstraction::UNKNOWN == currentScriptRun.script ) && ( TextAbstraction::EMOJI == script ) ) { - currentScriptRun.script = TextAbstraction::LATIN; currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; numberOfAllScriptCharacters = 0u; } @@ -342,12 +352,6 @@ void MultilanguageSupport::SetScripts( const Vector& text, if( 0u != currentScriptRun.characterRun.numberOfCharacters ) { - 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; @@ -374,7 +378,8 @@ void MultilanguageSupport::SetScripts( const Vector& text, void MultilanguageSupport::ValidateFonts( const Vector& text, const Vector& scripts, const Vector& fontDescriptions, - FontId defaultFontId, + const TextAbstraction::FontDescription& defaultFontDescription, + TextAbstraction::PointSize26Dot6 defaultFontPointSize, CharacterIndex startIndex, Length numberOfCharacters, Vector& fonts ) @@ -424,67 +429,45 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // Get the font client. TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - // Get the default font description and default size. - TextAbstraction::FontDescription defaultFontDescription; - TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE; - if( defaultFontId > 0u ) - { - fontClient.GetDescription( defaultFontId, defaultFontDescription ); - defaultPointSize = fontClient.GetPointSize( defaultFontId ); - } - - // Merge font descriptions - Vector fontIds; - fontIds.Resize( numberOfCharacters, defaultFontId ); - Vector isDefaultFont; - isDefaultFont.Resize( numberOfCharacters, true ); - MergeFontDescriptions( fontDescriptions, - fontIds, - isDefaultFont, - defaultFontDescription, - defaultPointSize, - startIndex, - numberOfCharacters ); - const Character* const textBuffer = text.Begin(); - const FontId* const fontIdsBuffer = fontIds.Begin(); - const bool* const isDefaultFontBuffer = isDefaultFont.Begin(); + + // Iterators of the script runs. Vector::ConstIterator scriptRunIt = scripts.Begin(); Vector::ConstIterator scriptRunEndIt = scripts.End(); bool isNewParagraphCharacter = false; - PointSize26Dot6 currentPointSize = defaultPointSize; - FontId currentFontId = 0u; - FontId previousFontId = 0u; bool isPreviousEmojiScript = false; - // Whether it's the first set of characters to be validated. - // Used in case the paragraph starts with characters common to all scripts. - bool isFirstSetToBeValidated = true; + // Description of fallback font which is selected at current iteration. + TextAbstraction::FontDescription selectedFontDescription; CharacterIndex lastCharacter = startIndex + numberOfCharacters; for( Length index = startIndex; index < lastCharacter; ++index ) { // Get the current character. const Character character = *( textBuffer + index ); + bool needSoftwareBoldening = false; + bool needSoftwareItalic = false; + + // new description for current character + TextAbstraction::FontDescription currentFontDescription; + TextAbstraction::PointSize26Dot6 currentFontPointSize = defaultFontPointSize; + bool isDefaultFont = true; + MergeFontDescriptions( fontDescriptions, + defaultFontDescription, + defaultFontPointSize, + index, + currentFontDescription, + currentFontPointSize, + isDefaultFont ); // Get the font for the current character. - FontId fontId = *( fontIdsBuffer + index - startIndex ); - - // Whether the font being validated for the current character is a default one not set by the user. - const bool isDefault = *( isDefaultFontBuffer + index - startIndex ); + FontId fontId = fontClient.GetFontId( currentFontDescription, currentFontPointSize ); // Get the script for the current character. - const Script script = GetScript( index, - scriptRunIt, - scriptRunEndIt ); - - // Get the current point size. - if( currentFontId != fontId ) - { - currentPointSize = fontClient.GetPointSize( fontId ); - currentFontId = fontId; - } + Script script = GetScript( index, + scriptRunIt, + scriptRunEndIt ); #ifdef DEBUG_ENABLED { @@ -505,11 +488,14 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // Check first in the cache of default fonts per script and size. - DefaultFonts* defaultFonts = *( defaultFontPerScriptCacheBuffer + script ); FontId cachedDefaultFontId = 0u; + DefaultFonts* defaultFonts = *( defaultFontPerScriptCacheBuffer + script ); if( NULL != defaultFonts ) { - cachedDefaultFontId = defaultFonts->FindFont( fontClient, currentPointSize ); + // This cache stores fall-back fonts. + cachedDefaultFontId = defaultFonts->FindFont( fontClient, + currentFontDescription, + currentFontPointSize ); } // Whether the cached default font is valid. @@ -518,6 +504,12 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // The font is valid if it matches with the default one for the current script and size and it's different than zero. isValidFont = isValidCachedDefaultFont && ( fontId == cachedDefaultFontId ); + if( isValidFont ) + { + // Check if the font supports the character. + isValidFont = fontClient.IsCharacterSupportedByFont( fontId, character ); + } + bool isCommonScript = false; bool isEmojiScript = TextAbstraction::EMOJI == script; @@ -536,7 +528,6 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, currentFontRun.fontId = fontId; } - // If the given font is not valid, it means either: // - there is no cached font for the current script yet or, // - the user has set a different font than the default one for the current script or, @@ -559,96 +550,92 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // supports the 'white space'. However, that font may not support the DEVANAGARI script. isCommonScript = TextAbstraction::IsCommonScript( character ); - if( isCommonScript ) + // Check in the valid fonts cache. + ValidateFontsPerScript* validateFontsPerScript = *( validFontsPerScriptCacheBuffer + script ); + + if( NULL != validateFontsPerScript ) { - if( isValidCachedDefaultFont && - ( isDefault || ( currentFontId == previousFontId ) ) && - !isEmojiScript ) + // This cache stores valid fonts set by the user. + isValidFont = validateFontsPerScript->IsValidFont( fontId ); + + // It may happen that a validated font for a script doesn't have all the glyphs for that script. + // i.e a font validated for the CJK script may contain glyphs for the chinese language but not for the Japanese. + if( isValidFont ) { - // At this point the character common for all scripts has no font assigned. - // If there is a valid previously cached default font for it, use that one. - fontId = cachedDefaultFontId; - isValidFont = true; + // Checks if the current character is supported by the font is needed. + isValidFont = fontClient.IsCharacterSupportedByFont( fontId, character ); } } - else + + if( !isValidFont ) // (2) { - // Check in the valid fonts cache. - ValidateFontsPerScript* validateFontsPerScript = *( validFontsPerScriptCacheBuffer + script ); + // The selected font is not stored in any cache. - if( NULL != validateFontsPerScript ) - { - isValidFont = validateFontsPerScript->IsValidFont( fontId ); - } + // Checks if the current character is supported by the selected font. + isValidFont = fontClient.IsCharacterSupportedByFont( fontId, character ); - if( !isValidFont ) // (2) + // Emojis are present in many monochrome fonts; prefer color by default. + if( isValidFont && + isEmojiScript ) { - // Use the font client to validate the font. const GlyphIndex glyphIndex = fontClient.GetGlyphIndex( fontId, character ); - // The font is valid if there is a glyph for that character. - isValidFont = 0u != glyphIndex; + // For color emojis, the font is valid if the glyph is a color glyph (the bitmap is RGBA). + isValidFont = fontClient.IsColorGlyph( fontId, glyphIndex ); + } - // Emojis are present in many monochrome fonts; prefer color by default. - if( isValidFont && - isEmojiScript ) + // If there is a valid font, cache it. + if( isValidFont && !isCommonScript ) + { + if( NULL == validateFontsPerScript ) { - const PixelData bitmap = fontClient.CreateBitmap( fontId, glyphIndex ); + validateFontsPerScript = new ValidateFontsPerScript(); - // For color emojis, the font is valid if the bitmap is RGBA. - isValidFont = bitmap && ( Pixel::BGRA8888 == bitmap.GetPixelFormat() ); + *( validFontsPerScriptCacheBuffer + script ) = validateFontsPerScript; } - // If there is a valid font, cache it. - if( isValidFont ) - { - if( NULL == validateFontsPerScript ) - { - validateFontsPerScript = new ValidateFontsPerScript(); + validateFontsPerScript->mValidFonts.PushBack( fontId ); + } - *( validFontsPerScriptCacheBuffer + script ) = validateFontsPerScript; - } + if( !isValidFont && ( fontId != cachedDefaultFontId ) && ( !TextAbstraction::IsNewParagraph( character ) )) // (3) + { + // The selected font by the user or the platform's default font has failed to validate the character. - validateFontsPerScript->mValidFonts.PushBack( fontId ); + // Checks if the previously discarted cached default font supports the character. + bool isValidCachedFont = false; + if( isValidCachedDefaultFont ) + { + isValidCachedFont = fontClient.IsCharacterSupportedByFont( cachedDefaultFontId, character ); } - if( !isValidFont ) // (3) + if( isValidCachedFont ) { - // The given font has not been validated. - - if( isValidCachedDefaultFont ) - { - // Use the cached default font for the script if there is one. - fontId = cachedDefaultFontId; - } - else - { - // There is no valid cached default font for the script. - - DefaultFonts* defaultFontsPerScript = NULL; + // Use the cached default font for the script if there is one. + fontId = cachedDefaultFontId; + } + else + { + // There is no valid cached default font for the script. - // Emojis are present in many monochrome fonts; prefer color by default. - const bool preferColor = ( TextAbstraction::EMOJI == script ); + DefaultFonts* defaultFontsPerScript = NULL; - // Find a fallback-font. - fontId = fontClient.FindFallbackFont( currentFontId, character, currentPointSize, preferColor ); + // Emojis are present in many monochrome fonts; prefer color by default. + const bool preferColor = ( TextAbstraction::EMOJI == script ); - if( 0u == fontId ) - { - // If the system does not support a suitable font, fallback to Latin - defaultFontsPerScript = *( defaultFontPerScriptCacheBuffer + TextAbstraction::LATIN ); - if( NULL != defaultFontsPerScript ) - { - fontId = defaultFontsPerScript->FindFont( fontClient, currentPointSize ); - } - } + // Find a fallback-font. + fontId = fontClient.FindFallbackFont( character, + currentFontDescription, + currentFontPointSize, + preferColor ); - if( 0u == fontId ) - { - fontId = fontClient.FindDefaultFont( UTF32_A, currentPointSize ); - } + if( 0u == fontId ) + { + fontId = fontClient.FindDefaultFont( UTF32_A, currentFontPointSize ); + } - // Cache the font. + if ( !isCommonScript && (script != TextAbstraction::UNKNOWN) ) + { + // Cache the font if it is not an unknown script if( NULL == defaultFontsPerScript ) { defaultFontsPerScript = *( defaultFontPerScriptCacheBuffer + script ); @@ -659,11 +646,11 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, *( defaultFontPerScriptCacheBuffer + script ) = defaultFontsPerScript; } } - defaultFontsPerScript->mFonts.PushBack( fontId ); + defaultFontsPerScript->Cache( currentFontDescription, fontId ); } - } // !isValidFont (3) - } // !isValidFont (2) - } // !isCommonScript + } + } // !isValidFont (3) + } // !isValidFont (2) } // !isValidFont (1) #ifdef DEBUG_ENABLED @@ -679,15 +666,22 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, } #endif - if( isFirstSetToBeValidated && !isCommonScript ) + if( fontId != currentFontRun.fontId ) { - currentFontRun.fontId = fontId; - isFirstSetToBeValidated = false; + fontClient.GetDescription(fontId,selectedFontDescription); } + // Developer sets bold to character but selected font cannot support it + needSoftwareBoldening = ( currentFontDescription.weight >= TextAbstraction::FontWeight::BOLD ) && ( selectedFontDescription.weight < TextAbstraction::FontWeight::BOLD ); + + // Developer sets italic to character but selected font cannot support it + needSoftwareItalic = ( currentFontDescription.slant == TextAbstraction::FontSlant::ITALIC ) && ( selectedFontDescription.slant < TextAbstraction::FontSlant::ITALIC ); + // The font is now validated. if( ( fontId != currentFontRun.fontId ) || - isNewParagraphCharacter ) + isNewParagraphCharacter || + // If font id is same as previous but style is diffrent, initialize new one + ( ( fontId == currentFontRun.fontId ) && ( ( needSoftwareBoldening != currentFontRun.softwareBold ) || ( needSoftwareItalic != currentFontRun.softwareItalic ) ) ) ) { // Current run needs to be stored and a new one initialized. @@ -702,11 +696,8 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters; currentFontRun.characterRun.numberOfCharacters = 0u; currentFontRun.fontId = fontId; - - if( isNewParagraphCharacter ) - { - isFirstSetToBeValidated = true; - } + currentFontRun.softwareItalic = needSoftwareItalic; + currentFontRun.softwareBold = needSoftwareBoldening; } // Add one more character to the run. @@ -714,7 +705,6 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, // Whether the current character is a new paragraph character. isNewParagraphCharacter = TextAbstraction::IsNewParagraph( character ); - previousFontId = currentFontId; isPreviousEmojiScript = isEmojiScript; } // end traverse characters.