/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
// 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-run-container.h>
namespace Dali
{
-
namespace Toolkit
{
-
namespace Text
{
-
-LogicalModelPtr LogicalModel::New()
-{
- return LogicalModelPtr( new LogicalModel() );
-}
-
-void LogicalModel::SetText( const Character* const text,
- Length numberOfCharacters )
+void FreeFontFamilyNames(Vector<FontDescriptionRun>& fontDescriptionRuns)
{
- if( 0u == numberOfCharacters )
+ for(Vector<FontDescriptionRun>::Iterator it = fontDescriptionRuns.Begin(),
+ endIt = fontDescriptionRuns.End();
+ it != endIt;
+ ++it)
{
- mText.Clear();
+ delete[](*it).familyName;
}
- else
- {
- mText.Resize( numberOfCharacters );
- memcpy( mText.Begin(), text, numberOfCharacters * sizeof( Character ) );
- }
-}
-Length LogicalModel::GetNumberOfCharacters() const
-{
- return mText.Count();
+ fontDescriptionRuns.Clear();
}
-void LogicalModel::GetText( Character* text,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
+void FreeEmbeddedItems(Vector<EmbeddedItem>& embeddedItem)
{
- 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
+ for(Vector<EmbeddedItem>::Iterator it = embeddedItem.Begin(),
+ endIt = embeddedItem.End();
+ it != endIt;
+ ++it)
{
- mScriptRuns.Resize( numberOfRuns );
- memcpy( mScriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) );
+ EmbeddedItem& item = *it;
+ delete[] item.url;
}
+
+ embeddedItem.Clear();
}
-void LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex,
- Length numberOfCharacters,
- ScriptRunIndex& firstScriptRun,
- Length& numberOfScriptRuns ) const
+void FreeAnchors(Vector<Anchor>& anchors)
{
- // 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();
- it != endIt;
- ++it )
+ for(auto&& anchor : anchors)
{
- 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[] anchor.href;
}
+
+ anchors.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
+Script LogicalModel::GetScript(CharacterIndex characterIndex) const
{
// If this operation is too slow, consider a binary search.
- for( Length index = 0u, length = mScriptRuns.Count(); index < length; ++index )
+ const ScriptRun* const scriptRunBuffer = mScriptRuns.Begin();
+ for(Length index = 0u, length = mScriptRuns.Count(); index < length; ++index)
{
- const ScriptRun* const scriptRun = mScriptRuns.Begin() + index;
+ const ScriptRun* const scriptRun = scriptRunBuffer + index;
- if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
- ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
+ if((scriptRun->characterRun.characterIndex <= characterIndex) &&
+ (characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters))
{
return scriptRun->script;
}
return TextAbstraction::UNKNOWN;
}
-void LogicalModel::ReplaceScripts( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const ScriptRun* const scriptRuns,
- Length numberOfCharactersToInsert )
+CharacterDirection LogicalModel::GetCharacterDirection(CharacterIndex characterIndex) const
{
-}
-
-void LogicalModel::SetFonts( const FontRun* const fonts,
- Length numberOfRuns )
-{
- if( 0u == numberOfRuns )
- {
- mFontRuns.Clear();
- }
- else
+ if(characterIndex >= mCharacterDirections.Count())
{
- mFontRuns.Resize( numberOfRuns );
- memcpy( mFontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) );
+ // The model has no right to left characters, so the vector of directions is void.
+ return false;
}
+
+ return *(mCharacterDirections.Begin() + characterIndex);
}
-void LogicalModel::GetNumberOfFontRuns( CharacterIndex characterIndex,
- Length numberOfCharacters,
- FontRunIndex& firstFontRun,
- Length& numberOfFontRuns ) const
+CharacterIndex LogicalModel::GetLogicalCursorIndex(CharacterIndex visualCursorIndex)
{
- // 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;
+ // The character's directions buffer.
+ const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
+
+ // The bidirectional line info.
+ const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
+
+ // Whether the paragraph starts with a right to left character.
+ const bool isRightToLeftParagraph = bidirectionalLineInfo->direction;
+
+ // The total number of characters of the line.
+ const Length lastCharacterIndex = bidirectionalLineInfo->characterRun.characterIndex + bidirectionalLineInfo->characterRun.numberOfCharacters;
- if( ( font.characterRun.characterIndex + font.characterRun.numberOfCharacters > characterIndex ) &&
- ( characterIndex + numberOfCharacters > font.characterRun.characterIndex ) )
+ CharacterIndex logicalCursorIndex = 0u;
+
+ if(bidirectionalLineInfo->characterRun.characterIndex == visualCursorIndex)
+ {
+ if(isRightToLeftParagraph)
{
- firstFontFound = true;
- ++numberOfFontRuns;
+ logicalCursorIndex = lastCharacterIndex;
}
- else if( lastCharacterIndex <= font.characterRun.characterIndex )
+ else // else logical position is the first of the line.
{
- // nothing else to do.
- break;
+ logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
}
-
- if( !firstFontFound )
+ }
+ else if(lastCharacterIndex == visualCursorIndex)
+ {
+ if(isRightToLeftParagraph)
+ {
+ logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
+ }
+ else // else logical position is the number of characters.
{
- ++firstFontRun;
+ logicalCursorIndex = lastCharacterIndex;
}
}
-}
-
-void LogicalModel::GetFontRuns( FontRun* fontRuns,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
-{
- FontRunIndex firstFontRun = 0u;
- Length numberOfFontRuns = 0u;
+ 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.
- GetNumberOfFontRuns( characterIndex,
- numberOfCharacters,
- firstFontRun,
- numberOfFontRuns );
+ const CharacterIndex previousVisualCursorIndex = visualCursorIndex - 1u;
+ const CharacterIndex previousLogicalCursorIndex = *(bidirectionalLineInfo->visualToLogicalMap + previousVisualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
+ const CharacterIndex currentLogicalCursorIndex = *(bidirectionalLineInfo->visualToLogicalMap + visualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
- memcpy( fontRuns, mFontRuns.Begin() + firstFontRun, numberOfFontRuns * sizeof( FontRun ) );
-}
+ const CharacterDirection previousCharacterDirection = *(modelCharacterDirections + previousLogicalCursorIndex);
+ const CharacterDirection currentCharacterDirection = *(modelCharacterDirections + currentLogicalCursorIndex);
-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 ) )
+ if(previousCharacterDirection == currentCharacterDirection)
+ {
+ // Both glyphs have the same direction.
+ if(previousCharacterDirection)
+ {
+ logicalCursorIndex = previousLogicalCursorIndex;
+ }
+ else
+ {
+ logicalCursorIndex = currentLogicalCursorIndex;
+ }
+ }
+ else
{
- return fontRun->fontId;
+ if(isRightToLeftParagraph)
+ {
+ if(currentCharacterDirection)
+ {
+ logicalCursorIndex = currentLogicalCursorIndex + 1u;
+ }
+ else
+ {
+ logicalCursorIndex = previousLogicalCursorIndex;
+ }
+ }
+ else
+ {
+ if(previousCharacterDirection)
+ {
+ logicalCursorIndex = currentLogicalCursorIndex;
+ }
+ else
+ {
+ logicalCursorIndex = previousLogicalCursorIndex + 1u;
+ }
+ }
}
}
- return 0u;
+ return logicalCursorIndex;
}
-void LogicalModel::ReplaceFonts( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const FontRun* const fontRuns,
- Length numberOfCharactersToInsert )
+CharacterIndex LogicalModel::GetLogicalCharacterIndex(CharacterIndex visualCharacterIndex)
{
+ // The bidirectional line info.
+ const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
+
+ return *(bidirectionalLineInfo->visualToLogicalMap + visualCharacterIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
}
-void LogicalModel::SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
- Length length )
+bool LogicalModel::FetchBidirectionalLineInfo(CharacterIndex characterIndex)
{
- if( 0u == length )
- {
- mLineBreakInfo.Clear();
- }
- else
+ // The number of bidirectional lines.
+ const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count();
+
+ if(0u == numberOfBidirectionalLines)
{
- mLineBreakInfo.Resize( length );
- memcpy( mLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) );
+ // If there is no bidirectional info.
+ return false;
}
-}
-void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
- CharacterIndex characterIndex,
- Length numberOfItems ) const
-{
- memcpy( lineBreakInfo, mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) );
-}
+ // Find the bidi line where the character is laid-out.
-LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const
-{
- return *( mLineBreakInfo.Begin() + characterIndex );
-}
+ const BidirectionalLineInfoRun* const bidirectionalLineInfoBuffer = mBidirectionalLineInfo.Begin();
-void LogicalModel::ReplaceLineBreakInfo( CharacterIndex characterIndex,
- Length numberOfItemsToRemove,
- const LineBreakInfo* const lineBreakInfo,
- Length numberOfItemsToInsert )
-{
-}
+ // Check first if the character is in the previously fetched line.
-void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
- Length length )
-{
- if( 0u == length )
+ BidirectionalLineRunIndex bidiLineIndex = 0u;
+ CharacterIndex lastCharacterOfRightToLeftRun = 0u;
+ if(mBidirectionalLineIndex < numberOfBidirectionalLines)
{
- mWordBreakInfo.Clear();
+ const BidirectionalLineInfoRun& bidiLineRun = *(bidirectionalLineInfoBuffer + mBidirectionalLineIndex);
+
+ const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
+ if((bidiLineRun.characterRun.characterIndex <= characterIndex) &&
+ (characterIndex < lastCharacterOfRunPlusOne))
+ {
+ // The character is in the previously fetched bidi line.
+ return true;
+ }
+ else
+ {
+ // The character is not in the previously fetched line.
+ // Set the bidi line index from where to start the fetch.
+
+ if(characterIndex < bidiLineRun.characterRun.characterIndex)
+ {
+ // Start the fetch from the beginning.
+ bidiLineIndex = 0u;
+ }
+ else
+ {
+ // Start the fetch from the next line.
+ bidiLineIndex = mBidirectionalLineIndex + 1u;
+ lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
+ }
+ }
}
- else
+
+ // The character has not been found in the previously fetched bidi line.
+ for(Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLineInfoBuffer + bidiLineIndex,
+ endIt = mBidirectionalLineInfo.End();
+ it != endIt;
+ ++it, ++bidiLineIndex)
{
- mWordBreakInfo.Resize( length );
- memcpy( mWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) );
+ const BidirectionalLineInfoRun& bidiLineRun = *it;
+
+ if((lastCharacterOfRightToLeftRun < characterIndex) &&
+ (characterIndex < bidiLineRun.characterRun.characterIndex))
+ {
+ // The character is not inside a bidi line.
+ return false;
+ }
+
+ const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
+ lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
+ if((bidiLineRun.characterRun.characterIndex <= characterIndex) &&
+ (characterIndex < lastCharacterOfRunPlusOne))
+ {
+ // Bidi line found. Fetch the line.
+ mBidirectionalLineIndex = bidiLineIndex;
+ return true;
+ }
}
-}
-void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
- CharacterIndex characterIndex,
- Length numberOfItems ) const
-{
- memcpy( wordBreakInfo, mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) );
+ return false;
}
-WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const
+BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const
{
- return *( mWordBreakInfo.Begin() + characterIndex );
+ return mBidirectionalLineIndex;
}
-void LogicalModel::ReplaceWordBreakInfo( CharacterIndex characterIndex,
- Length numberOfItemsToRemove,
- const WordBreakInfo* const wordBreakInfo,
- Length numberOfItemsToInsert )
+void LogicalModel::UpdateTextStyleRuns(CharacterIndex index, int numberOfCharacters)
{
+ const Length totalNumberOfCharacters = mText.Count();
+
+ // Process the color runs.
+ Vector<ColorRun> removedColorRuns;
+ UpdateCharacterRuns<ColorRun>(index,
+ numberOfCharacters,
+ totalNumberOfCharacters,
+ mColorRuns,
+ removedColorRuns);
+
+ // Process the background color runs.
+ Vector<ColorRun> removedBackgroundColorRuns;
+ UpdateCharacterRuns<ColorRun>(index,
+ numberOfCharacters,
+ totalNumberOfCharacters,
+ mBackgroundColorRuns,
+ removedBackgroundColorRuns);
+
+ // 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::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
- Length numberOfRuns )
+void LogicalModel::RetrieveStyle(CharacterIndex index, InputStyle& style)
{
- if( 0u == numberOfRuns )
+ 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)
{
- mBidirectionalParagraphInfo.Clear();
+ const ColorRun& colorRun = *it;
+
+ if((colorRun.characterRun.characterIndex <= index) &&
+ (index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters))
+ {
+ colorIndex = runIndex;
+ colorOverriden = true;
+ }
}
- else
+
+ // Set the text's color if it's overriden.
+ if(colorOverriden)
{
- mBidirectionalParagraphInfo.Resize( numberOfRuns );
- memcpy( mBidirectionalParagraphInfo.Begin(), bidirectionalInfo, numberOfRuns * sizeof( BidirectionalParagraphInfoRun ) );
+ style.textColor = (*(colorRunsBuffer + colorIndex)).color;
+ style.isDefaultColor = false;
}
-}
-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 )
+ // 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 BidirectionalParagraphInfoRun& bidi = *it;
+ const FontDescriptionRun& fontDescriptionRun = *it;
- if( ( bidi.characterRun.characterIndex + bidi.characterRun.numberOfCharacters > characterIndex ) &&
- ( characterIndex + numberOfCharacters > bidi.characterRun.characterIndex ) )
+ if((fontDescriptionRun.characterRun.characterIndex <= index) &&
+ (index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters))
{
- firstParagraphFound = true;
- ++numberOfFontRuns;
- }
+ if(fontDescriptionRun.familyDefined)
+ {
+ nameIndex = runIndex;
+ nameOverriden = true;
+ }
- if( !firstParagraphFound )
- {
- ++firstBidirectionalRun;
+ 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;
+ }
}
}
-}
-void LogicalModel::GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
-{
- BidirectionalRunIndex firstBidirectionalRun = 0u;
- Length numberOfFontRuns = 0u;
+ // Set the font's family name if it's overriden.
+ if(nameOverriden)
+ {
+ const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + nameIndex);
- GetNumberOfBidirectionalInfoRuns( characterIndex,
- numberOfCharacters,
- firstBidirectionalRun,
- numberOfFontRuns );
+ style.familyName = std::string(fontDescriptionRun.familyName, fontDescriptionRun.familyLength);
+ style.isFamilyDefined = true;
+ }
- memcpy( bidirectionalInfo, mBidirectionalParagraphInfo.Begin() + firstBidirectionalRun, numberOfFontRuns * sizeof( BidirectionalParagraphInfoRun ) );
-}
+ // Set the font's weight if it's overriden.
+ if(weightOverriden)
+ {
+ const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + weightIndex);
-void ReplaceBidirectionalInfo( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const BidirectionalParagraphInfoRun* const bidirectionalInfo,
- Length numberOfCharactersToInsert )
-{
-}
+ style.weight = fontDescriptionRun.weight;
+ style.isWeightDefined = true;
+ }
-void LogicalModel::SetCharacterDirections( const CharacterDirection* const directions,
- Length numberOfCharacters )
-{
- if( 0u == numberOfCharacters )
+ // Set the font's width if it's overriden.
+ if(widthOverriden)
{
- mCharacterDirections.Clear();
+ const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + widthIndex);
+
+ style.width = fontDescriptionRun.width;
+ style.isWidthDefined = true;
}
- else
+
+ // Set the font's slant if it's overriden.
+ if(slantOverriden)
{
- mCharacterDirections.Resize( numberOfCharacters );
- memcpy( mCharacterDirections.Begin(), directions, numberOfCharacters * sizeof( CharacterDirection ) );
+ const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + slantIndex);
+
+ style.slant = fontDescriptionRun.slant;
+ style.isSlantDefined = true;
}
-}
-void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
-{
- if( 0u == mCharacterDirections.Count() )
+ // Set the font's size if it's overriden.
+ if(sizeOverriden)
{
- // Nothing to retrieve if the model has no right to left characters.
- return;
+ const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + sizeIndex);
+
+ style.size = static_cast<float>(fontDescriptionRun.size) / 64.f;
+ style.isSizeDefined = true;
}
+}
- memcpy( directions, mCharacterDirections.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterDirection ) );
+void LogicalModel::ClearFontDescriptionRuns()
+{
+ FreeFontFamilyNames(mFontDescriptionRuns);
}
-CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
+void LogicalModel::CreateParagraphInfo(CharacterIndex startIndex,
+ Length numberOfCharacters)
{
- if( characterIndex >= mCharacterDirections.Count() )
+ const Length totalNumberOfCharacters = mLineBreakInfo.Count();
+
+ // Count the number of LINE_MUST_BREAK to reserve some space for the vector of paragraph's info.
+ Vector<CharacterIndex> paragraphs;
+ paragraphs.Reserve(numberOfCharacters);
+ const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = mLineBreakInfo.Begin();
+ const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
+ for(Length index = startIndex; index < lastCharacterIndexPlusOne; ++index)
{
- // The model has no right to left characters, so the vector of directions is void.
- return false;
+ if(TextAbstraction::LINE_MUST_BREAK == *(lineBreakInfoBuffer + index))
+ {
+ paragraphs.PushBack(index);
+ }
}
- return *( mCharacterDirections.Begin() + characterIndex );
-}
+ // Whether the current paragraphs are updated or set from scratch.
+ const bool updateCurrentParagraphs = numberOfCharacters < totalNumberOfCharacters;
-void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
- Length numberOfRuns )
-{
- if( 0u == numberOfRuns )
+ // Reserve space for current paragraphs plus new ones.
+ const Length numberOfNewParagraphs = paragraphs.Count();
+ const Length totalNumberOfParagraphs = mParagraphInfo.Count() + numberOfNewParagraphs;
+ mParagraphInfo.Resize(totalNumberOfParagraphs);
+
+ ParagraphRun* paragraphInfoBuffer = NULL;
+ Vector<ParagraphRun> newParagraphs;
+
+ if(updateCurrentParagraphs)
{
- mVisualToLogicalMap.Clear();
- mLogicalToVisualMap.Clear();
+ newParagraphs.Resize(numberOfNewParagraphs);
+ paragraphInfoBuffer = newParagraphs.Begin();
}
else
{
- const Length numberOfCharacters = mText.Count();
- mVisualToLogicalMap.Resize( numberOfCharacters );
- mLogicalToVisualMap.Resize( numberOfCharacters );
+ paragraphInfoBuffer = mParagraphInfo.Begin();
+ }
- CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
- CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
+ // Find where to insert the new paragraphs.
+ ParagraphRunIndex paragraphIndex = 0u;
+ CharacterIndex firstIndex = startIndex;
- CharacterIndex lastIndex = 0u;
- for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
+ if(updateCurrentParagraphs)
+ {
+ for(Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
+ endIt = mParagraphInfo.Begin() + totalNumberOfParagraphs - numberOfNewParagraphs;
+ it != endIt;
+ ++it)
{
- const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
+ const ParagraphRun& paragraph(*it);
- if( lastIndex < bidiLineInfo.characterRun.characterIndex )
+ if(startIndex < paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters)
{
- // Fill with the identity.
- for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
- {
- *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
- }
+ firstIndex = paragraph.characterRun.characterIndex;
+ break;
}
- // Fill the conversion table of the run.
- for( CharacterIndex index = 0u;
- index < bidiLineInfo.characterRun.numberOfCharacters;
- ++index, ++lastIndex )
- {
- *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
- }
+ ++paragraphIndex;
}
+ }
- // Complete with the identity if there are some left to right characters after the last right to left.
- for( ; lastIndex < numberOfCharacters; ++lastIndex )
- {
- *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
- }
+ // Create the paragraph info.
+ ParagraphRunIndex newParagraphIndex = 0u;
+ for(Vector<CharacterIndex>::ConstIterator it = paragraphs.Begin(),
+ endIt = paragraphs.End();
+ it != endIt;
+ ++it, ++newParagraphIndex)
+ {
+ const CharacterIndex index = *it;
+
+ ParagraphRun& paragraph = *(paragraphInfoBuffer + newParagraphIndex);
+ paragraph.characterRun.characterIndex = firstIndex;
+ paragraph.characterRun.numberOfCharacters = 1u + index - firstIndex;
+
+ firstIndex += paragraph.characterRun.numberOfCharacters;
+ }
+
+ // Insert the new paragraphs.
+ if(updateCurrentParagraphs)
+ {
+ mParagraphInfo.Insert(mParagraphInfo.Begin() + paragraphIndex,
+ newParagraphs.Begin(),
+ newParagraphs.End());
- // Sets the logical to visual conversion map.
- for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+ mParagraphInfo.Resize(totalNumberOfParagraphs);
+
+ // Update the next paragraph indices.
+ for(Vector<ParagraphRun>::Iterator it = mParagraphInfo.Begin() + paragraphIndex + newParagraphs.Count(),
+ endIt = mParagraphInfo.End();
+ it != endIt;
+ ++it)
{
- *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
+ ParagraphRun& paragraph(*it);
+
+ paragraph.characterRun.characterIndex += numberOfCharacters;
}
}
}
-void LogicalModel::ReplaceVisualToLogicalMap( CharacterIndex characterIndex,
- Length numberOfCharactersToRemove,
- const BidirectionalLineInfoRun* const bidirectionalInfo,
- Length numberOfCharactersToInsert )
+void LogicalModel::FindParagraphs(CharacterIndex index,
+ Length numberOfCharacters,
+ Vector<ParagraphRunIndex>& paragraphs)
{
-}
+ // Reserve som space for the paragraph indices.
+ paragraphs.Reserve(mParagraphInfo.Count());
-CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
-{
- if( 0u == mLogicalToVisualMap.Count() )
+ // Traverse the paragraphs to find which ones contain the given characters.
+ ParagraphRunIndex paragraphIndex = 0u;
+ for(Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
+ endIt = mParagraphInfo.End();
+ it != endIt;
+ ++it, ++paragraphIndex)
{
- // If there is no logical to visual info is because the whole text is left to right.
- // Return the identity.
- return logicalCharacterIndex;
- }
-
- return *( mLogicalToVisualMap.Begin() + logicalCharacterIndex );
-}
+ const ParagraphRun& paragraph(*it);
-CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
-{
- if( 0u == mVisualToLogicalMap.Count() )
- {
- // If there is no visual to logical info is because the whole text is left to right.
- // Return the identity.
- return visualCharacterIndex;
+ if((paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters > index) &&
+ (paragraph.characterRun.characterIndex < index + numberOfCharacters))
+ {
+ paragraphs.PushBack(paragraphIndex);
+ }
}
-
- return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
}
-void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
+void LogicalModel::ClearEmbeddedImages()
{
- memcpy( logicalToVisualMap, mLogicalToVisualMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
+ FreeEmbeddedItems(mEmbeddedItems);
}
-void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
- CharacterIndex characterIndex,
- Length numberOfCharacters ) const
+void LogicalModel::ClearAnchors()
{
- memcpy( visualToLogicalMap, mVisualToLogicalMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
+ FreeAnchors(mAnchors);
}
LogicalModel::~LogicalModel()
{
+ ClearFontDescriptionRuns();
+ ClearEmbeddedImages();
}
LogicalModel::LogicalModel()
+: mBidirectionalLineIndex(0u)
{
}