2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/text/multi-language-support-impl.h>
22 #include <dali/public-api/adaptor-framework/singleton-service.h>
23 #include <dali-toolkit/public-api/text/logical-model.h>
24 #include <dali-toolkit/public-api/text/font-run.h>
25 #include <dali-toolkit/public-api/text/script.h>
26 #include <dali-toolkit/public-api/text/script-run.h>
27 #include <dali/integration-api/debug.h>
42 * @brief Retrieves the font Id from the font run for a given character's @p index.
44 * If the character's index exceeds the current font run it increases the iterator to get the next one.
46 * @param[in] index The character's index.
47 * @param[in,out] fontRunIt Iterator to the current font run.
48 * @param[in] fontRunEndIt Iterator to one after the last font run.
50 * @return The font id.
52 FontId GetFontId( Length index,
53 Vector<FontRun>::ConstIterator& fontRunIt,
54 const Vector<FontRun>::ConstIterator& fontRunEndIt )
58 if( fontRunIt != fontRunEndIt )
60 const FontRun& fontRun = *fontRunIt;
62 if( ( index >= fontRun.characterRun.characterIndex ) &&
63 ( index < fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) )
65 fontId = fontRun.fontId;
68 if( index == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters )
70 // All the characters of the current run have been traversed. Get the next one for the next iteration.
79 * @brief Retrieves the script Id from the script run for a given character's @p index.
81 * If the character's index exceeds the current script run it increases the iterator to get the next one.
83 * @param[in] index The character's index.
84 * @param[in,out] scriptRunIt Iterator to the current font run.
85 * @param[in] scriptRunEndIt Iterator to one after the last script run.
89 Script GetScript( Length index,
90 Vector<ScriptRun>::ConstIterator& scriptRunIt,
91 const Vector<ScriptRun>::ConstIterator& scriptRunEndIt )
93 Script script = TextAbstraction::UNKNOWN;
95 if( scriptRunIt != scriptRunEndIt )
97 const ScriptRun& scriptRun = *scriptRunIt;
99 if( ( index >= scriptRun.characterRun.characterIndex ) &&
100 ( index < scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) )
102 script = scriptRun.script;
105 if( index == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
107 // All the characters of the current run have been traversed. Get the next one for the next iteration.
115 bool ValidateFontsPerScript::FindValidFont( FontId fontId ) const
117 for( Vector<FontId>::ConstIterator it = mValidFonts.Begin(),
118 endIt = mValidFonts.End();
131 MultilanguageSupport::MultilanguageSupport()
132 : mDefaultFontPerScriptCache(),
133 mValidFontsPerScriptCache()
135 // Initializes the default font cache to zero (invalid font).
136 // Reserves space to cache the default fonts and access them with the script as an index.
137 mDefaultFontPerScriptCache.Resize( TextAbstraction::UNKNOWN, 0u );
139 // Initializes the valid fonts cache to NULL (no valid fonts).
140 // Reserves space to cache the valid fonts and access them with the script as an index.
141 mValidFontsPerScriptCache.Resize( TextAbstraction::UNKNOWN, NULL );
144 MultilanguageSupport::~MultilanguageSupport()
146 // Destroy the valid fonts per script cache.
148 for( Vector<ValidateFontsPerScript*>::Iterator it = mValidFontsPerScriptCache.Begin(),
149 endIt = mValidFontsPerScriptCache.End();
157 Text::MultilanguageSupport MultilanguageSupport::Get()
159 Text::MultilanguageSupport multilanguageSupportHandle;
161 SingletonService service( SingletonService::Get() );
164 // Check whether the singleton is already created
165 Dali::BaseHandle handle = service.GetSingleton( typeid( Text::MultilanguageSupport ) );
168 // If so, downcast the handle
169 MultilanguageSupport* impl = dynamic_cast< Internal::MultilanguageSupport* >( handle.GetObjectPtr() );
170 multilanguageSupportHandle = Text::MultilanguageSupport( impl );
172 else // create and register the object
174 multilanguageSupportHandle = Text::MultilanguageSupport( new MultilanguageSupport );
175 service.Register( typeid( multilanguageSupportHandle ), multilanguageSupportHandle );
179 return multilanguageSupportHandle;
182 void MultilanguageSupport::SetScripts( LogicalModel& model )
184 // 1) Retrieve the text from the model.
185 const Length numberOfCharacters = model.GetNumberOfCharacters();
187 if( 0u == numberOfCharacters )
189 // Nothing to do if there are no characters.
193 Vector<Character> text;
194 text.Resize( numberOfCharacters );
198 numberOfCharacters );
200 // 2) Traverse all characters and set the scripts.
202 // Stores the current script run.
203 ScriptRun currentScriptRun;
204 currentScriptRun.characterRun.characterIndex = 0u;
205 currentScriptRun.characterRun.numberOfCharacters = 0u;
206 currentScriptRun.script = TextAbstraction::UNKNOWN;
208 // Temporary stores the script runs.
209 std::vector<ScriptRun> scriptRuns;
210 scriptRuns.reserve( numberOfCharacters << 2u ); // To reduce the number of reallocations.
212 for( Vector<Character>::ConstIterator it = text.Begin(),
217 const Character character = *it;
219 Script script = GetCharacterScript( character );
221 if( TextAbstraction::UNKNOWN == script )
223 script = TextAbstraction::LATIN;
224 DALI_ASSERT_DEBUG( !"MultilanguageSupport::SetScripts. Unkown script!" );
227 if( script != currentScriptRun.script )
229 // Current run needs to be stored and a new one initialized.
231 if( 0u != currentScriptRun.characterRun.numberOfCharacters )
233 // Store the script run.
234 scriptRuns.push_back( currentScriptRun );
237 // Initialize the new one.
238 currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters;
239 currentScriptRun.characterRun.numberOfCharacters = 0u;
240 currentScriptRun.script = script;
243 // Add one more character to the run.
244 ++currentScriptRun.characterRun.numberOfCharacters;
247 if( 0u != currentScriptRun.characterRun.numberOfCharacters )
249 // Store the last run.
250 scriptRuns.push_back( currentScriptRun );
253 // 3) Set the script runs into the model.
255 model.SetScripts( &scriptRuns[0u],
259 void MultilanguageSupport::ValidateFonts( LogicalModel& model )
261 // 1) Retrieve the text from the model.
262 const Length numberOfCharacters = model.GetNumberOfCharacters();
264 if( 0u == numberOfCharacters )
266 // Nothing to do if there are no characters.
270 Vector<Character> text;
271 text.Resize( numberOfCharacters );
273 Character* textBuffer = text.Begin();
276 numberOfCharacters );
278 // 2) Retrieve any font previously set.
280 const Length numberOfFontRuns = model.GetNumberOfFontRuns( 0u, numberOfCharacters );
282 Vector<FontRun> fontRuns;
283 fontRuns.Reserve( numberOfFontRuns );
285 FontRun* fontRunsBuffer = fontRuns.Begin();
286 model.GetFontRuns( fontRunsBuffer,
288 numberOfCharacters );
290 // 3) Retrieve the scripts from the model.
292 const Length numberOfScriptRuns = model.GetNumberOfScriptRuns( 0u, numberOfCharacters );
294 Vector<ScriptRun> scriptRuns;
295 scriptRuns.Reserve( numberOfScriptRuns );
297 ScriptRun* scriptRunsBuffer = scriptRuns.Begin();
298 model.GetScriptRuns( scriptRunsBuffer,
300 numberOfCharacters );
302 // 4) Traverse the characters and validate/set the fonts.
305 FontId* defaultFontPerScriptCacheBuffer = mDefaultFontPerScriptCache.Begin();
306 ValidateFontsPerScript** validFontsPerScriptCacheBuffer = mValidFontsPerScriptCache.Begin();
308 // Stores the validated font runs.
309 Vector<FontRun> validatedFontRuns;
310 validatedFontRuns.Reserve( numberOfFontRuns );
312 // Initializes a validated font run.
313 FontRun currentFontRun;
314 currentFontRun.characterRun.characterIndex = 0u;
315 currentFontRun.characterRun.numberOfCharacters = 0u;
316 currentFontRun.fontId = 0u;
317 currentFontRun.isDefault = false;
319 // Get the font client.
320 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
322 // Iterators of the font and script runs.
323 Vector<FontRun>::ConstIterator fontRunIt = fontRuns.Begin();
324 Vector<FontRun>::ConstIterator fontRunEndIt = fontRuns.End();
325 Vector<ScriptRun>::ConstIterator scriptRunIt = scriptRuns.Begin();
326 Vector<ScriptRun>::ConstIterator scriptRunEndIt = scriptRuns.End();
328 for( Length index = 0u; index < numberOfCharacters; ++index )
330 // Get the character.
331 const Character character = *( textBuffer + index );
333 // Get the font for the character.
334 FontId fontId = GetFontId( index,
338 // Get the script for the character.
339 Script script = GetScript( index,
343 if( TextAbstraction::UNKNOWN == script )
345 DALI_LOG_WARNING( "MultilanguageSupport::ValidateFonts. Unknown script!" );
346 script = TextAbstraction::LATIN;
349 // Whether the font being validated is a default one not set by the user.
350 const bool isDefault = ( 0u == fontId );
352 // The default font point size.
353 PointSize26Dot6 pointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
357 // Validate if the font set by the user supports the character.
359 // Check first in the caches.
361 // The user may have set the default font. Check it. Otherwise check in the valid fonts cache.
362 if( fontId != *( defaultFontPerScriptCacheBuffer + script ) )
364 // Check in the valid fonts cache.
365 ValidateFontsPerScript* validateFontsPerScript = *( validFontsPerScriptCacheBuffer + script );
366 if( NULL != validateFontsPerScript )
368 if( !validateFontsPerScript->FindValidFont( fontId ) )
370 // Use the font client to validate the font.
371 const GlyphIndex glyphIndex = fontClient.GetGlyphIndex( fontId, character );
373 if( 0u == glyphIndex )
375 // Get the point size of the current font. It will be used to get a default font id.
376 pointSize = fontClient.GetPointSize( fontId );
378 // The font is not valid. Set to zero and a default one will be set.
383 // Add the font to the valid font cache.
384 validateFontsPerScript->mValidFonts.PushBack( fontId );
390 // Use the font client to validate the font.
391 const GlyphIndex glyphIndex = fontClient.GetGlyphIndex( fontId, character );
393 if( 0u == glyphIndex )
395 // Get the point size of the current font. It will be used to get a default font id.
396 pointSize = fontClient.GetPointSize( fontId );
398 // The font is not valid. Set to zero and a default one will be set.
403 // Add the font to the valid font cache.
404 validateFontsPerScript = new ValidateFontsPerScript();
405 *( validFontsPerScriptCacheBuffer + script ) = validateFontsPerScript;
407 validateFontsPerScript->mValidFonts.PushBack( fontId );
413 // The font has not been validated. Find a default one.
416 // The character has no font assigned. Get a default one from the cache
417 fontId = *( defaultFontPerScriptCacheBuffer + script );
419 // If the cache has not a default font, get one from the font client.
422 // Find a default font.
423 fontId = fontClient.FindDefaultFont( character, pointSize );
426 *( defaultFontPerScriptCacheBuffer + script ) = fontId;
430 // The font is now validated.
432 if( ( fontId != currentFontRun.fontId ) ||
433 ( isDefault != currentFontRun.isDefault ) )
435 // Current run needs to be stored and a new one initialized.
437 if( 0u != currentFontRun.characterRun.numberOfCharacters )
439 // Store the font run.
440 validatedFontRuns.PushBack( currentFontRun );
443 // Initialize the new one.
444 currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters;
445 currentFontRun.characterRun.numberOfCharacters = 0u;
446 currentFontRun.fontId = fontId;
447 currentFontRun.isDefault = isDefault;
450 // Add one more character to the run.
451 ++currentFontRun.characterRun.numberOfCharacters;
454 if( 0u != currentFontRun.characterRun.numberOfCharacters )
456 // Store the last run.
457 validatedFontRuns.PushBack( currentFontRun );
460 // 5) Sets the validated font runs to the model.
461 model.SetFonts( validatedFontRuns.Begin(),
462 validatedFontRuns.Count() );
465 } // namespace Internal
469 } // namespace Toolkit