// CLASS HEADER
#include <dali-toolkit/internal/text/logical-model-impl.h>
-// EXTERNAL INCLUDES
-#include <memory.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/input-style.h>
+#include <dali-toolkit/internal/text/text-style-run-container.h>
namespace Dali
{
namespace Text
{
-LogicalModelPtr LogicalModel::New()
-{
- return LogicalModelPtr( new LogicalModel() );
-}
-
-void LogicalModel::SetText( const Character* const text,
- Length numberOfCharacters )
-{
- if( 0u == numberOfCharacters )
- {
- mText.Clear();
- }
- else
- {
- mText.Resize( numberOfCharacters );
- memcpy( mText.Begin(), text, numberOfCharacters * sizeof( Character ) );
- }
-}
-
-Length LogicalModel::GetNumberOfCharacters() const
+void FreeFontFamilyNames( Vector<FontDescriptionRun>& fontDescriptionRuns )
{
- return mText.Count();
-}
-
-void LogicalModel::GetText( Character* text,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
-{
- memcpy( text, mText.Begin() + characterIndex, numberOfCharacters * sizeof( Character ) );
-}
-
-Character LogicalModel::GetCharacter( CharacterIndex characterIndex ) const
-{
- return mText[characterIndex];
-}
-
-void LogicalModel::ReplaceText( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const Character* const text,
- Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetScripts( const ScriptRun* const scripts,
- Length numberOfRuns )
-{
- if( 0u == numberOfRuns )
- {
- mScriptRuns.Clear();
- }
- else
- {
- mScriptRuns.Resize( numberOfRuns );
- memcpy( mScriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) );
- }
-}
-
-void LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex,
- Length numberOfCharacters,
- ScriptRunIndex& firstScriptRun,
- Length& numberOfScriptRuns ) const
-{
- // Initialize the number of scripts and the index to the first script.
- firstScriptRun = 0u;
- numberOfScriptRuns = 0;
- bool firstScriptFound = false;
-
- const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
-
- // Traverse the scripts and count those scripts within the range of characters.
- for( Vector<ScriptRun>::ConstIterator it = mScriptRuns.Begin(),
- endIt = mScriptRuns.End();
+ for( Vector<FontDescriptionRun>::Iterator it = fontDescriptionRuns.Begin(),
+ endIt = fontDescriptionRuns.End();
it != endIt;
++it )
{
- const ScriptRun& script = *it;
-
- if( ( script.characterRun.characterIndex + script.characterRun.numberOfCharacters > characterIndex ) &&
- ( lastCharacterIndex > script.characterRun.characterIndex ) )
- {
- firstScriptFound = true;
- ++numberOfScriptRuns;
- }
- else if( lastCharacterIndex <= script.characterRun.characterIndex )
- {
- // nothing else to do.
- break;
- }
-
- if( !firstScriptFound )
- {
- ++firstScriptRun;
- }
+ delete (*it).familyName;
}
+
+ fontDescriptionRuns.Clear();
}
-void LogicalModel::GetScriptRuns( ScriptRun* scriptRuns,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
+LogicalModelPtr LogicalModel::New()
{
- ScriptRunIndex firstScriptRun = 0u;
- Length numberOfScriptRuns = 0u;
-
- GetNumberOfScriptRuns( characterIndex,
- numberOfCharacters,
- firstScriptRun,
- numberOfScriptRuns );
-
- memcpy( scriptRuns, mScriptRuns.Begin() + firstScriptRun, numberOfScriptRuns * sizeof( ScriptRun ) );
+ return LogicalModelPtr( new LogicalModel() );
}
Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
return TextAbstraction::UNKNOWN;
}
-void LogicalModel::ReplaceScripts( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const ScriptRun* const scriptRuns,
- Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetFonts( const FontRun* const fonts,
- Length numberOfRuns )
-{
- if( 0u == numberOfRuns )
- {
- mFontRuns.Clear();
- }
- else
- {
- mFontRuns.Resize( numberOfRuns );
- memcpy( mFontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) );
- }
-}
-
-void LogicalModel::GetNumberOfFontRuns( CharacterIndex characterIndex,
- Length numberOfCharacters,
- FontRunIndex& firstFontRun,
- Length& numberOfFontRuns ) const
-{
- // Initialize the number of fonts and the index to the first font.
- firstFontRun = 0u;
- numberOfFontRuns = 0;
- bool firstFontFound = false;
-
- const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
-
- // Traverse the fonts and count those fonts within the range of characters.
- for( Vector<FontRun>::ConstIterator it = mFontRuns.Begin(),
- endIt = mFontRuns.End();
- it != endIt;
- ++it )
- {
- const FontRun& font = *it;
-
- if( ( font.characterRun.characterIndex + font.characterRun.numberOfCharacters > characterIndex ) &&
- ( characterIndex + numberOfCharacters > font.characterRun.characterIndex ) )
- {
- firstFontFound = true;
- ++numberOfFontRuns;
- }
- else if( lastCharacterIndex <= font.characterRun.characterIndex )
- {
- // nothing else to do.
- break;
- }
-
- if( !firstFontFound )
- {
- ++firstFontRun;
- }
- }
-}
-
-void LogicalModel::GetFontRuns( FontRun* fontRuns,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
-{
- FontRunIndex firstFontRun = 0u;
- Length numberOfFontRuns = 0u;
-
- GetNumberOfFontRuns( characterIndex,
- numberOfCharacters,
- firstFontRun,
- numberOfFontRuns );
-
- memcpy( fontRuns, mFontRuns.Begin() + firstFontRun, numberOfFontRuns * sizeof( FontRun ) );
-}
-
-FontId LogicalModel::GetFont( CharacterIndex characterIndex ) const
-{
- for( Length index = 0u, length = mFontRuns.Count(); index < length; ++index )
- {
- const FontRun* const fontRun = mFontRuns.Begin() + index;
-
- if( ( fontRun->characterRun.characterIndex <= characterIndex ) &&
- ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) )
- {
- return fontRun->fontId;
- }
- }
-
- return 0u;
-}
-
-void LogicalModel::ReplaceFonts( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const FontRun* const fontRuns,
- Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
- Length length )
-{
- if( 0u == length )
- {
- mLineBreakInfo.Clear();
- }
- else
- {
- mLineBreakInfo.Resize( length );
- memcpy( mLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) );
- }
-}
-
-void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
- CharacterIndex characterIndex,
- Length numberOfItems ) const
-{
- memcpy( lineBreakInfo, mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) );
-}
-
-LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const
-{
- return *( mLineBreakInfo.Begin() + characterIndex );
-}
-
-void LogicalModel::ReplaceLineBreakInfo( CharacterIndex characterIndex,
- Length numberOfItemsToRemove,
- const LineBreakInfo* const lineBreakInfo,
- Length numberOfItemsToInsert )
-{
-}
-
-void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
- Length length )
-{
- if( 0u == length )
- {
- mWordBreakInfo.Clear();
- }
- else
- {
- mWordBreakInfo.Resize( length );
- memcpy( mWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) );
- }
-}
-
-void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
- CharacterIndex characterIndex,
- Length numberOfItems ) const
-{
- memcpy( wordBreakInfo, mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) );
-}
-
-WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const
-{
- return *( mWordBreakInfo.Begin() + characterIndex );
-}
-
-void LogicalModel::ReplaceWordBreakInfo( CharacterIndex characterIndex,
- Length numberOfItemsToRemove,
- const WordBreakInfo* const wordBreakInfo,
- Length numberOfItemsToInsert )
-{
-}
-
-void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
- Length numberOfRuns )
-{
- if( 0u == numberOfRuns )
- {
- mBidirectionalParagraphInfo.Clear();
- }
- else
- {
- mBidirectionalParagraphInfo.Resize( numberOfRuns );
- memcpy( mBidirectionalParagraphInfo.Begin(), bidirectionalInfo, numberOfRuns * sizeof( BidirectionalParagraphInfoRun ) );
- }
-}
-
-void LogicalModel::GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
- Length numberOfCharacters,
- BidirectionalRunIndex& firstBidirectionalRun,
- Length& numberOfFontRuns ) const
-{
- // Initialize the number of bidi paragraphs and the index to the first paragraph.
- firstBidirectionalRun = 0u;
- numberOfFontRuns = 0;
- bool firstParagraphFound = false;
-
- // Traverse the bidirectional paragraph info and count those bidi paragraphs within the range of characters.
- for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = mBidirectionalParagraphInfo.Begin(),
- endIt = mBidirectionalParagraphInfo.End();
- it != endIt;
- ++it )
- {
- const BidirectionalParagraphInfoRun& bidi = *it;
-
- if( ( bidi.characterRun.characterIndex + bidi.characterRun.numberOfCharacters > characterIndex ) &&
- ( characterIndex + numberOfCharacters > bidi.characterRun.characterIndex ) )
- {
- firstParagraphFound = true;
- ++numberOfFontRuns;
- }
-
- if( !firstParagraphFound )
- {
- ++firstBidirectionalRun;
- }
- }
-}
-
-void LogicalModel::GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
-{
- BidirectionalRunIndex firstBidirectionalRun = 0u;
- Length numberOfFontRuns = 0u;
-
- GetNumberOfBidirectionalInfoRuns( characterIndex,
- numberOfCharacters,
- firstBidirectionalRun,
- numberOfFontRuns );
-
- memcpy( bidirectionalInfo, mBidirectionalParagraphInfo.Begin() + firstBidirectionalRun, numberOfFontRuns * sizeof( BidirectionalParagraphInfoRun ) );
-}
-
-void ReplaceBidirectionalInfo( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const BidirectionalParagraphInfoRun* const bidirectionalInfo,
- Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetCharacterDirections( const CharacterDirection* const directions,
- Length numberOfCharacters )
-{
- if( 0u == numberOfCharacters )
- {
- mCharacterDirections.Clear();
- }
- else
- {
- mCharacterDirections.Resize( numberOfCharacters );
- memcpy( mCharacterDirections.Begin(), directions, numberOfCharacters * sizeof( CharacterDirection ) );
- }
-}
-
-void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
-{
- if( 0u == mCharacterDirections.Count() )
- {
- // Nothing to retrieve if the model has no right to left characters.
- return;
- }
-
- memcpy( directions, mCharacterDirections.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterDirection ) );
-}
-
CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
{
if( characterIndex >= mCharacterDirections.Count() )
{
mVisualToLogicalMap.Clear();
mLogicalToVisualMap.Clear();
+ mVisualToLogicalCursorMap.Clear();
}
else
{
mVisualToLogicalMap.Resize( numberOfCharacters );
mLogicalToVisualMap.Resize( numberOfCharacters );
+ const Length numberOfCharactersPlus = numberOfCharacters + 1u;
+ mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
+
CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
+ CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
+
CharacterIndex lastIndex = 0u;
for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
{
{
*( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
}
- }
-}
-void LogicalModel::ReplaceVisualToLogicalMap( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const BidirectionalLineInfoRun* const bidirectionalInfo,
- Length numberOfCharactersToInsert )
-{
-}
+ // Sets the visual to logical conversion map for cursor positions.
-CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
-{
- if( 0u == mLogicalToVisualMap.Count() )
- {
- // If there is no logical to visual info is because the whole text is left to right.
- // Return the identity.
- return logicalCharacterIndex;
- }
+ const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
+ BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
+ BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
+
+ const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
+
+ Length bidirectionalParagraphIndex = 0u;
+ bool isRightToLeftParagraph = false;
+ for( CharacterIndex index = 0u; index < numberOfCharactersPlus; ++index )
+ {
+ if( bidirectionalParagraph &&
+ ( bidirectionalParagraph->characterRun.characterIndex == index ) )
+ {
+ isRightToLeftParagraph = *( modelCharacterDirections + index );
+ }
+
+ if( 0u == index )
+ {
+ if( isRightToLeftParagraph )
+ {
+ *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
+ }
+ else // else logical position is zero.
+ {
+ *( modelVisualToLogicalCursorMap + index ) = 0u;
+ }
+ }
+ else if( numberOfCharacters == index )
+ {
+ if( isRightToLeftParagraph )
+ {
+ *( modelVisualToLogicalCursorMap + index ) = 0u;
+ }
+ else // else logical position is the number of characters.
+ {
+ *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
+ }
+ }
+ else
+ {
+ // Get the character indexed by index - 1 and index
+ // and calculate the logical position according the directions of
+ // both characters and the direction of the paragraph.
+
+ const CharacterIndex previousIndex = index - 1u;
+ const CharacterIndex logicalPosition0 = *( modelVisualToLogicalMapBuffer + previousIndex );
+ const CharacterIndex logicalPosition1 = *( modelVisualToLogicalMapBuffer + index );
+
+ const CharacterDirection direction0 = *( modelCharacterDirections + logicalPosition0 );
+ const CharacterDirection direction1 = *( modelCharacterDirections + logicalPosition1 );
+
+ if( direction0 == direction1 )
+ {
+ // Both glyphs have the same direction.
+ if( direction0 )
+ {
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
+ }
+ else
+ {
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
+ }
+ }
+ else
+ {
+ if( isRightToLeftParagraph )
+ {
+ if( direction1 )
+ {
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
+ }
+ else
+ {
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
+ }
+ }
+ else
+ {
+ if( direction0 )
+ {
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
+ }
+ else
+ {
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
+ }
+ }
+ }
+ }
- return *( mLogicalToVisualMap.Begin() + logicalCharacterIndex );
+ if( bidirectionalParagraph &&
+ ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
+ {
+ isRightToLeftParagraph = false;
+ ++bidirectionalParagraphIndex;
+ if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
+ {
+ bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
+ }
+ else
+ {
+ bidirectionalParagraph = NULL;
+ }
+ }
+ }
+ }
}
CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
}
-void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
+void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters )
{
- memcpy( logicalToVisualMap, mLogicalToVisualMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
+ const Length totalNumberOfCharacters = mText.Count();
+
+ // Process the color runs.
+ Vector<ColorRun> removedColorRuns;
+ UpdateCharacterRuns<ColorRun>( index,
+ numberOfCharacters,
+ totalNumberOfCharacters,
+ mColorRuns,
+ removedColorRuns );
+
+ // Process the font description runs.
+ Vector<FontDescriptionRun> removedFontDescriptionRuns;
+ UpdateCharacterRuns<FontDescriptionRun>( index,
+ numberOfCharacters,
+ totalNumberOfCharacters,
+ mFontDescriptionRuns,
+ removedFontDescriptionRuns );
+
+ // Free memory allocated for the font family name.
+ FreeFontFamilyNames( removedFontDescriptionRuns );
+}
+
+void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
+{
+ unsigned int runIndex = 0u;
+
+ // Set the text color.
+ bool colorOverriden = false;
+ unsigned int colorIndex = 0u;
+ const ColorRun* const colorRunsBuffer = mColorRuns.Begin();
+ for( Vector<ColorRun>::ConstIterator it = colorRunsBuffer,
+ endIt = mColorRuns.End();
+ it != endIt;
+ ++it, ++runIndex )
+ {
+ const ColorRun& colorRun = *it;
+
+ if( ( colorRun.characterRun.characterIndex <= index ) &&
+ ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) )
+ {
+ colorIndex = runIndex;
+ colorOverriden = true;
+ }
+ }
+
+ // Set the text's color if it's overriden.
+ if( colorOverriden )
+ {
+ style.textColor = ( *( colorRunsBuffer + colorIndex ) ).color;
+ }
+
+ // Reset the run index.
+ runIndex = 0u;
+
+ // Set the font's parameters.
+ bool nameOverriden = false;
+ bool weightOverriden = false;
+ bool widthOverriden = false;
+ bool slantOverriden = false;
+ bool sizeOverriden = false;
+ unsigned int nameIndex = 0u;
+ unsigned int weightIndex = 0u;
+ unsigned int widthIndex = 0u;
+ unsigned int slantIndex = 0u;
+ unsigned int sizeIndex = 0u;
+ const FontDescriptionRun* const fontDescriptionRunsBuffer = mFontDescriptionRuns.Begin();
+ for( Vector<FontDescriptionRun>::ConstIterator it = fontDescriptionRunsBuffer,
+ endIt = mFontDescriptionRuns.End();
+ it != endIt;
+ ++it, ++runIndex )
+ {
+ const FontDescriptionRun& fontDescriptionRun = *it;
+
+ if( ( fontDescriptionRun.characterRun.characterIndex <= index ) &&
+ ( index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters ) )
+ {
+ if( fontDescriptionRun.familyDefined )
+ {
+ nameIndex = runIndex;
+ nameOverriden = true;
+ }
+
+ if( fontDescriptionRun.weightDefined )
+ {
+ weightIndex = runIndex;
+ weightOverriden = true;
+ }
+
+ if( fontDescriptionRun.widthDefined )
+ {
+ widthIndex = runIndex;
+ widthOverriden = true;
+ }
+
+ if( fontDescriptionRun.slantDefined )
+ {
+ slantIndex = runIndex;
+ slantOverriden = true;
+ }
+
+ if( fontDescriptionRun.sizeDefined )
+ {
+ sizeIndex = runIndex;
+ sizeOverriden = true;
+ }
+ }
+ }
+
+ // Set the font's family name if it's overriden.
+ if( nameOverriden )
+ {
+ const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + nameIndex );
+
+ style.familyName = std::string( fontDescriptionRun.familyName, fontDescriptionRun.familyLength );
+ style.familyDefined = true;
+ }
+
+ // Set the font's weight if it's overriden.
+ if( weightOverriden )
+ {
+ const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + weightIndex );
+
+ style.weight = fontDescriptionRun.weight;
+ style.weightDefined = true;
+ }
+
+ // Set the font's width if it's overriden.
+ if( widthOverriden )
+ {
+ const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + widthIndex );
+
+ style.width = fontDescriptionRun.width;
+ style.widthDefined = true;
+ }
+
+ // Set the font's slant if it's overriden.
+ if( slantOverriden )
+ {
+ const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + slantIndex );
+
+ style.slant = fontDescriptionRun.slant;
+ style.slantDefined = true;
+ }
+
+ // Set the font's size if it's overriden.
+ if( sizeOverriden )
+ {
+ const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + sizeIndex );
+
+ style.size = static_cast<float>( fontDescriptionRun.size ) / 64.f;
+ style.sizeDefined = true;
+ }
+
+ // Reset the run index.
+ runIndex = 0u;
}
-void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
+void LogicalModel::ClearFontDescriptionRuns()
{
- memcpy( visualToLogicalMap, mVisualToLogicalMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
+ FreeFontFamilyNames( mFontDescriptionRuns );
}
LogicalModel::~LogicalModel()
{
+ ClearFontDescriptionRuns();
}
LogicalModel::LogicalModel()