+void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
+{
+ // Calculate the operations to be done.
+ const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
+
+ Vector<Character>& utf32Characters = mLogicalModel->mText;
+
+ const Length numberOfCharacters = utf32Characters.Count();
+
+ Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
+ if( GET_LINE_BREAKS & operations )
+ {
+ // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
+ // calculate the bidirectional info for each 'paragraph'.
+ // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
+ // is not shaped together).
+ lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
+
+ SetLineBreakInfo( utf32Characters,
+ lineBreakInfo );
+ }
+
+ Vector<WordBreakInfo>& wordBreakInfo = mLogicalModel->mWordBreakInfo;
+ if( GET_WORD_BREAKS & operations )
+ {
+ // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
+ wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
+
+ SetWordBreakInfo( utf32Characters,
+ wordBreakInfo );
+ }
+
+ const bool getScripts = GET_SCRIPTS & operations;
+ const bool validateFonts = VALIDATE_FONTS & operations;
+
+ Vector<ScriptRun>& scripts = mLogicalModel->mScriptRuns;
+ Vector<FontRun>& validFonts = mLogicalModel->mFontRuns;
+
+ if( getScripts || validateFonts )
+ {
+ // Validates the fonts assigned by the application or assigns default ones.
+ // It makes sure all the characters are going to be rendered by the correct font.
+ MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+ if( getScripts )
+ {
+ // Retrieves the scripts used in the text.
+ multilanguageSupport.SetScripts( utf32Characters,
+ lineBreakInfo,
+ scripts );
+ }
+
+ if( validateFonts )
+ {
+ if( 0u == validFonts.Count() )
+ {
+ // Copy the requested font defaults received via the property system.
+ // These may not be valid i.e. may not contain glyphs for the necessary scripts.
+ GetDefaultFonts( validFonts, numberOfCharacters );
+ }
+
+ // Validates the fonts. If there is a character with no assigned font it sets a default one.
+ // After this call, fonts are validated.
+ multilanguageSupport.ValidateFonts( utf32Characters,
+ scripts,
+ validFonts );
+ }
+ }
+
+ Vector<Character> mirroredUtf32Characters;
+ bool textMirrored = false;
+ if( BIDI_INFO & operations )
+ {
+ // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
+ // bidirectional info.
+
+ Length numberOfParagraphs = 0u;
+
+ const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+ for( Length index = 0u; index < numberOfCharacters; ++index )
+ {
+ if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
+ {
+ ++numberOfParagraphs;
+ }
+ }
+
+ Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
+ bidirectionalInfo.Reserve( numberOfParagraphs );
+
+ // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+ SetBidirectionalInfo( utf32Characters,
+ scripts,
+ lineBreakInfo,
+ bidirectionalInfo );
+
+ if( 0u != bidirectionalInfo.Count() )
+ {
+ // This paragraph has right to left text. Some characters may need to be mirrored.
+ // TODO: consider if the mirrored string can be stored as well.
+
+ textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
+
+ // Only set the character directions if there is right to left characters.
+ Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
+ directions.Resize( numberOfCharacters );
+
+ GetCharactersDirection( bidirectionalInfo,
+ directions );
+ }
+ else
+ {
+ // There is no right to left characters. Clear the directions vector.
+ mLogicalModel->mCharacterDirections.Clear();
+ }
+
+ }
+
+ Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
+ Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
+ Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
+ if( SHAPE_TEXT & operations )
+ {
+ const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
+ // Shapes the text.
+ ShapeText( textToShape,
+ lineBreakInfo,
+ scripts,
+ validFonts,
+ glyphs,
+ glyphsToCharactersMap,
+ charactersPerGlyph );
+
+ // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+ mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
+ mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
+ }
+
+ const Length numberOfGlyphs = glyphs.Count();
+
+ if( GET_GLYPH_METRICS & operations )
+ {
+ mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
+ }
+}
+
+void Controller::Impl::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
+{
+ if( mFontDefaults )
+ {
+ FontRun fontRun;
+ fontRun.characterRun.characterIndex = 0;
+ fontRun.characterRun.numberOfCharacters = numberOfCharacters;
+ fontRun.fontId = mFontDefaults->GetFontId( mFontClient );
+ fontRun.isDefault = true;
+
+ fonts.PushBack( fontRun );
+ }
+}
+