X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Flogical-model-impl.cpp;h=9ad00bc3031e7dd87d28f38243f763cf02a33d84;hp=80d6595442b4274a2cb63adab8db30bfc0c91fcf;hb=29bbe2381a1cfdd96757dfd441e7f9747560b2c8;hpb=43810310547ea62237f91305e8b9724fd017492a diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp index 80d6595..9ad00bc 100644 --- a/dali-toolkit/internal/text/logical-model-impl.cpp +++ b/dali-toolkit/internal/text/logical-model-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -18,521 +18,630 @@ // CLASS HEADER #include -// EXTERNAL INCLUDES -#include +// INTERNAL INCLUDES +#include +#include +#include namespace Dali { - namespace Toolkit { - namespace Text { - -LogicalModelPtr LogicalModel::New() +void FreeFontFamilyNames(Vector& fontDescriptionRuns) { - return LogicalModelPtr( new LogicalModel() ); + for(Vector::Iterator it = fontDescriptionRuns.Begin(), + endIt = fontDescriptionRuns.End(); + it != endIt; + ++it) + { + delete[](*it).familyName; + } + + fontDescriptionRuns.Clear(); } -void LogicalModel::SetText( const Character* const text, - Length numberOfCharacters ) +void FreeEmbeddedItems(Vector& embeddedItem) { - if( 0u == numberOfCharacters ) + for(Vector::Iterator it = embeddedItem.Begin(), + endIt = embeddedItem.End(); + it != endIt; + ++it) { - mText.Clear(); + EmbeddedItem& item = *it; + delete[] item.url; } - else - { - mText.Resize( numberOfCharacters ); - memcpy( mText.Begin(), text, numberOfCharacters * sizeof( Character ) ); - } -} -Length LogicalModel::GetNumberOfCharacters() const -{ - return mText.Count(); + embeddedItem.Clear(); } -void LogicalModel::GetText( Character* text, - CharacterIndex characterIndex, - Length numberOfCharacters ) const +void FreeAnchors(Vector& anchors) { - memcpy( text, mText.Begin() + characterIndex, numberOfCharacters * sizeof( Character ) ); -} + for(auto&& anchor : anchors) + { + delete[] anchor.href; + } -Character LogicalModel::GetCharacter( CharacterIndex characterIndex ) const -{ - return mText[characterIndex]; + anchors.Clear(); } -void LogicalModel::ReplaceText( CharacterIndex characterIndex, - Length numberOfCharactersToRemove, - const Character* const text, - Length numberOfCharactersToInsert ) +LogicalModelPtr LogicalModel::New() { + return LogicalModelPtr(new LogicalModel()); } -void LogicalModel::SetScripts( const ScriptRun* const scripts, - Length numberOfRuns ) +Script LogicalModel::GetScript(CharacterIndex characterIndex) const { - if( 0u == numberOfRuns ) + // If this operation is too slow, consider a binary search. + + const ScriptRun* const scriptRunBuffer = mScriptRuns.Begin(); + for(Length index = 0u, length = mScriptRuns.Count(); index < length; ++index) { - mScriptRuns.Clear(); + const ScriptRun* const scriptRun = scriptRunBuffer + index; + + if((scriptRun->characterRun.characterIndex <= characterIndex) && + (characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters)) + { + return scriptRun->script; + } } - else + + return TextAbstraction::UNKNOWN; +} + +CharacterDirection LogicalModel::GetCharacterDirection(CharacterIndex characterIndex) const +{ + if(characterIndex >= mCharacterDirections.Count()) { - mScriptRuns.Resize( numberOfRuns ); - memcpy( mScriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) ); + // The model has no right to left characters, so the vector of directions is void. + return false; } + + return *(mCharacterDirections.Begin() + characterIndex); } -void LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex, - Length numberOfCharacters, - ScriptRunIndex& firstScriptRun, - Length& numberOfScriptRuns ) const +CharacterIndex LogicalModel::GetLogicalCursorIndex(CharacterIndex visualCursorIndex) { - // 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::ConstIterator it = mScriptRuns.Begin(), - endIt = mScriptRuns.End(); - it != endIt; - ++it ) - { - const ScriptRun& script = *it; + // The character's directions buffer. + const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin(); - if( ( script.characterRun.characterIndex + script.characterRun.numberOfCharacters > characterIndex ) && - ( lastCharacterIndex > script.characterRun.characterIndex ) ) + // 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; + + CharacterIndex logicalCursorIndex = 0u; + + if(bidirectionalLineInfo->characterRun.characterIndex == visualCursorIndex) + { + if(isRightToLeftParagraph) { - firstScriptFound = true; - ++numberOfScriptRuns; + logicalCursorIndex = lastCharacterIndex; } - else if( lastCharacterIndex <= script.characterRun.characterIndex ) + else // else logical position is the first of the line. { - // nothing else to do. - break; + logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex; } - - if( !firstScriptFound ) + } + else if(lastCharacterIndex == visualCursorIndex) + { + if(isRightToLeftParagraph) + { + logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex; + } + else // else logical position is the number of characters. { - ++firstScriptRun; + logicalCursorIndex = lastCharacterIndex; } } -} - -void LogicalModel::GetScriptRuns( ScriptRun* scriptRuns, - CharacterIndex characterIndex, - Length numberOfCharacters ) const -{ - ScriptRunIndex firstScriptRun = 0u; - Length numberOfScriptRuns = 0u; - - GetNumberOfScriptRuns( characterIndex, - numberOfCharacters, - firstScriptRun, - numberOfScriptRuns ); - - memcpy( scriptRuns, mScriptRuns.Begin() + firstScriptRun, numberOfScriptRuns * sizeof( ScriptRun ) ); -} + 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. -Script LogicalModel::GetScript( CharacterIndex characterIndex ) const -{ - // If this operation is too slow, consider a binary search. + 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; - for( Length index = 0u, length = mScriptRuns.Count(); index < length; ++index ) - { - const ScriptRun* const scriptRun = mScriptRuns.Begin() + index; + const CharacterDirection previousCharacterDirection = *(modelCharacterDirections + previousLogicalCursorIndex); + const CharacterDirection currentCharacterDirection = *(modelCharacterDirections + currentLogicalCursorIndex); - if( ( scriptRun->characterRun.characterIndex <= characterIndex ) && - ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) ) + if(previousCharacterDirection == currentCharacterDirection) { - return scriptRun->script; + // Both glyphs have the same direction. + if(previousCharacterDirection) + { + logicalCursorIndex = previousLogicalCursorIndex; + } + else + { + logicalCursorIndex = currentLogicalCursorIndex; + } + } + else + { + if(isRightToLeftParagraph) + { + if(currentCharacterDirection) + { + logicalCursorIndex = currentLogicalCursorIndex + 1u; + } + else + { + logicalCursorIndex = previousLogicalCursorIndex; + } + } + else + { + if(previousCharacterDirection) + { + logicalCursorIndex = currentLogicalCursorIndex; + } + else + { + logicalCursorIndex = previousLogicalCursorIndex + 1u; + } + } } } - return TextAbstraction::UNKNOWN; + return logicalCursorIndex; } -void LogicalModel::ReplaceScripts( CharacterIndex characterIndex, - Length numberOfCharactersToRemove, - const ScriptRun* const scriptRuns, - 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::SetFonts( const FontRun* const fonts, - Length numberOfRuns ) +bool LogicalModel::FetchBidirectionalLineInfo(CharacterIndex characterIndex) { - if( 0u == numberOfRuns ) - { - mFontRuns.Clear(); - } - else + // The number of bidirectional lines. + const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count(); + + if(0u == numberOfBidirectionalLines) { - mFontRuns.Resize( numberOfRuns ); - memcpy( mFontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) ); + // If there is no bidirectional info. + return false; } -} -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::ConstIterator it = mFontRuns.Begin(), - endIt = mFontRuns.End(); - it != endIt; - ++it ) + // Find the bidi line where the character is laid-out. + + const BidirectionalLineInfoRun* const bidirectionalLineInfoBuffer = mBidirectionalLineInfo.Begin(); + + // Check first if the character is in the previously fetched line. + + BidirectionalLineRunIndex bidiLineIndex = 0u; + CharacterIndex lastCharacterOfRightToLeftRun = 0u; + if(mBidirectionalLineIndex < numberOfBidirectionalLines) { - const FontRun& font = *it; + const BidirectionalLineInfoRun& bidiLineRun = *(bidirectionalLineInfoBuffer + mBidirectionalLineIndex); - if( ( font.characterRun.characterIndex + font.characterRun.numberOfCharacters > characterIndex ) && - ( characterIndex + numberOfCharacters > font.characterRun.characterIndex ) ) + const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters; + if((bidiLineRun.characterRun.characterIndex <= characterIndex) && + (characterIndex < lastCharacterOfRunPlusOne)) { - firstFontFound = true; - ++numberOfFontRuns; + // The character is in the previously fetched bidi line. + return true; } - else if( lastCharacterIndex <= font.characterRun.characterIndex ) + else { - // nothing else to do. - break; - } + // The character is not in the previously fetched line. + // Set the bidi line index from where to start the fetch. - if( !firstFontFound ) - { - ++firstFontRun; + 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; + } } } -} -void LogicalModel::GetFontRuns( FontRun* fontRuns, - CharacterIndex characterIndex, - Length numberOfCharacters ) const -{ - FontRunIndex firstFontRun = 0u; - Length numberOfFontRuns = 0u; + // The character has not been found in the previously fetched bidi line. + for(Vector::ConstIterator it = bidirectionalLineInfoBuffer + bidiLineIndex, + endIt = mBidirectionalLineInfo.End(); + it != endIt; + ++it, ++bidiLineIndex) + { + const BidirectionalLineInfoRun& bidiLineRun = *it; - GetNumberOfFontRuns( characterIndex, - numberOfCharacters, - firstFontRun, - numberOfFontRuns ); + if((lastCharacterOfRightToLeftRun < characterIndex) && + (characterIndex < bidiLineRun.characterRun.characterIndex)) + { + // The character is not inside a bidi line. + return false; + } - memcpy( fontRuns, mFontRuns.Begin() + firstFontRun, numberOfFontRuns * sizeof( FontRun ) ); -} + 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; + } + } -FontId LogicalModel::GetFont( CharacterIndex characterIndex ) const -{ - for( Length index = 0u, length = mFontRuns.Count(); index < length; ++index ) + return false; +} + +BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const +{ + return mBidirectionalLineIndex; +} + +void LogicalModel::UpdateTextStyleRuns(CharacterIndex index, int numberOfCharacters) +{ + const Length totalNumberOfCharacters = mText.Count(); + + // Process the color runs. + Vector removedColorRuns; + UpdateCharacterRuns(index, + numberOfCharacters, + totalNumberOfCharacters, + mColorRuns, + removedColorRuns); + + // This is needed until now for underline tag in mark-up processor + // Process the underlined runs. + Vector removedUnderlinedCharacterRuns; + UpdateCharacterRuns(index, + numberOfCharacters, + totalNumberOfCharacters, + mUnderlinedCharacterRuns, + removedUnderlinedCharacterRuns); + + // Process the strikethrough runs. + Vector removedStrikethroughCharacterRuns; + UpdateCharacterRuns(index, + numberOfCharacters, + totalNumberOfCharacters, + mStrikethroughCharacterRuns, + removedStrikethroughCharacterRuns); + + // Process the background color runs. + Vector removedBackgroundColorRuns; + UpdateCharacterRuns(index, + numberOfCharacters, + totalNumberOfCharacters, + mBackgroundColorRuns, + removedBackgroundColorRuns); + + // Process the font description runs. + Vector removedFontDescriptionRuns; + UpdateCharacterRuns(index, + numberOfCharacters, + totalNumberOfCharacters, + mFontDescriptionRuns, + removedFontDescriptionRuns); + + // Free memory allocated for the font family name. + FreeFontFamilyNames(removedFontDescriptionRuns); + + // Process the bounded paragraph runs + MergeBoundedParagraphRunsWhenRemoveCharacters(mText, + index, + numberOfCharacters, + mBoundedParagraphRuns); + + Vector removedBoundedParagraphRuns; + UpdateCharacterRuns(index, + numberOfCharacters, + totalNumberOfCharacters, + mBoundedParagraphRuns, + removedBoundedParagraphRuns); +} + +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::ConstIterator it = colorRunsBuffer, + endIt = mColorRuns.End(); + it != endIt; + ++it, ++runIndex) { - const FontRun* const fontRun = mFontRuns.Begin() + index; + const ColorRun& colorRun = *it; - if( ( fontRun->characterRun.characterIndex <= characterIndex ) && - ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) ) + if((colorRun.characterRun.characterIndex <= index) && + (index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters)) { - return fontRun->fontId; + colorIndex = runIndex; + colorOverriden = true; } } - 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 ) + // Set the text's color if it's overriden. + if(colorOverriden) { - mLineBreakInfo.Clear(); + style.textColor = (*(colorRunsBuffer + colorIndex)).color; + style.isDefaultColor = false; } - else + + // 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::ConstIterator it = fontDescriptionRunsBuffer, + endIt = mFontDescriptionRuns.End(); + it != endIt; + ++it, ++runIndex) { - mLineBreakInfo.Resize( length ); - memcpy( mLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) ); - } -} + const FontDescriptionRun& fontDescriptionRun = *it; -void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo, - CharacterIndex characterIndex, - Length numberOfItems ) const -{ - memcpy( lineBreakInfo, mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) ); -} + if((fontDescriptionRun.characterRun.characterIndex <= index) && + (index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters)) + { + if(fontDescriptionRun.familyDefined) + { + nameIndex = runIndex; + nameOverriden = true; + } -LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const -{ - return *( mLineBreakInfo.Begin() + characterIndex ); -} + if(fontDescriptionRun.weightDefined) + { + weightIndex = runIndex; + weightOverriden = true; + } -void LogicalModel::ReplaceLineBreakInfo( CharacterIndex characterIndex, - Length numberOfItemsToRemove, - const LineBreakInfo* const lineBreakInfo, - Length numberOfItemsToInsert ) -{ -} + if(fontDescriptionRun.widthDefined) + { + widthIndex = runIndex; + widthOverriden = true; + } -void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo, - Length length ) -{ - if( 0u == length ) - { - mWordBreakInfo.Clear(); + if(fontDescriptionRun.slantDefined) + { + slantIndex = runIndex; + slantOverriden = true; + } + + if(fontDescriptionRun.sizeDefined) + { + sizeIndex = runIndex; + sizeOverriden = true; + } + } } - else + + // Set the font's family name if it's overriden. + if(nameOverriden) { - mWordBreakInfo.Resize( length ); - memcpy( mWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) ); - } -} + const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + nameIndex); -void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo, - CharacterIndex characterIndex, - Length numberOfItems ) const -{ - memcpy( wordBreakInfo, mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) ); -} + style.familyName = std::string(fontDescriptionRun.familyName, fontDescriptionRun.familyLength); + style.isFamilyDefined = true; + } -WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const -{ - return *( mWordBreakInfo.Begin() + characterIndex ); -} + // Set the font's weight if it's overriden. + if(weightOverriden) + { + const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + weightIndex); -void LogicalModel::ReplaceWordBreakInfo( CharacterIndex characterIndex, - Length numberOfItemsToRemove, - const WordBreakInfo* const wordBreakInfo, - Length numberOfItemsToInsert ) -{ -} + style.weight = fontDescriptionRun.weight; + style.isWeightDefined = true; + } -void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo, - Length numberOfRuns ) -{ - if( 0u == numberOfRuns ) + // Set the font's width if it's overriden. + if(widthOverriden) { - mBidirectionalParagraphInfo.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) { - mBidirectionalParagraphInfo.Resize( numberOfRuns ); - memcpy( mBidirectionalParagraphInfo.Begin(), bidirectionalInfo, numberOfRuns * sizeof( BidirectionalParagraphInfoRun ) ); + const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + slantIndex); + + style.slant = fontDescriptionRun.slant; + style.isSlantDefined = true; } -} -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::ConstIterator it = mBidirectionalParagraphInfo.Begin(), - endIt = mBidirectionalParagraphInfo.End(); - it != endIt; - ++it ) + // Set the font's size if it's overriden. + if(sizeOverriden) { - const BidirectionalParagraphInfoRun& bidi = *it; + const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + sizeIndex); - if( ( bidi.characterRun.characterIndex + bidi.characterRun.numberOfCharacters > characterIndex ) && - ( characterIndex + numberOfCharacters > bidi.characterRun.characterIndex ) ) - { - firstParagraphFound = true; - ++numberOfFontRuns; - } - - if( !firstParagraphFound ) - { - ++firstBidirectionalRun; - } + style.size = static_cast(fontDescriptionRun.size) / 64.f; + style.isSizeDefined = true; } } -void LogicalModel::GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo, - CharacterIndex characterIndex, - Length numberOfCharacters ) const +void LogicalModel::ClearFontDescriptionRuns() { - BidirectionalRunIndex firstBidirectionalRun = 0u; - Length numberOfFontRuns = 0u; - - GetNumberOfBidirectionalInfoRuns( characterIndex, - numberOfCharacters, - firstBidirectionalRun, - numberOfFontRuns ); - - memcpy( bidirectionalInfo, mBidirectionalParagraphInfo.Begin() + firstBidirectionalRun, numberOfFontRuns * sizeof( BidirectionalParagraphInfoRun ) ); + FreeFontFamilyNames(mFontDescriptionRuns); } -void ReplaceBidirectionalInfo( CharacterIndex characterIndex, - Length numberOfCharactersToRemove, - const BidirectionalParagraphInfoRun* const bidirectionalInfo, - Length numberOfCharactersToInsert ) +void LogicalModel::ClearStrikethroughRuns() { + mStrikethroughCharacterRuns.Clear(); } -void LogicalModel::SetCharacterDirections( const CharacterDirection* const directions, - Length numberOfCharacters ) +void LogicalModel::CreateParagraphInfo(CharacterIndex startIndex, + Length numberOfCharacters) { - if( 0u == numberOfCharacters ) - { - mCharacterDirections.Clear(); - } - else - { - mCharacterDirections.Resize( numberOfCharacters ); - memcpy( mCharacterDirections.Begin(), directions, numberOfCharacters * sizeof( CharacterDirection ) ); - } -} + const Length totalNumberOfCharacters = mLineBreakInfo.Count(); -void LogicalModel::GetCharacterDirections( CharacterDirection* directions, - CharacterIndex characterIndex, - Length numberOfCharacters ) const -{ - if( 0u == mCharacterDirections.Count() ) + // Count the number of LINE_MUST_BREAK to reserve some space for the vector of paragraph's info. + Vector paragraphs; + paragraphs.Reserve(numberOfCharacters); + const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = mLineBreakInfo.Begin(); + const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters; + for(Length index = startIndex; index < lastCharacterIndexPlusOne; ++index) { - // Nothing to retrieve if the model has no right to left characters. - return; + if(TextAbstraction::LINE_MUST_BREAK == *(lineBreakInfoBuffer + index)) + { + paragraphs.PushBack(index); + } } - memcpy( directions, mCharacterDirections.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterDirection ) ); -} + // Whether the current paragraphs are updated or set from scratch. + const bool updateCurrentParagraphs = numberOfCharacters < totalNumberOfCharacters; -CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const -{ - if( characterIndex >= mCharacterDirections.Count() ) - { - // The model has no right to left characters, so the vector of directions is void. - return false; - } + // Reserve space for current paragraphs plus new ones. + const Length numberOfNewParagraphs = paragraphs.Count(); + const Length totalNumberOfParagraphs = mParagraphInfo.Count() + numberOfNewParagraphs; + mParagraphInfo.Resize(totalNumberOfParagraphs); - return *( mCharacterDirections.Begin() + characterIndex ); -} + ParagraphRun* paragraphInfoBuffer = NULL; + Vector newParagraphs; -void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo, - Length numberOfRuns ) -{ - if( 0u == numberOfRuns ) + 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::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::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::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& 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::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; - } + const ParagraphRun& paragraph(*it); - return *( mLogicalToVisualMap.Begin() + logicalCharacterIndex ); + if((paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters > index) && + (paragraph.characterRun.characterIndex < index + numberOfCharacters)) + { + paragraphs.PushBack(paragraphIndex); + } + } } -CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const +Length LogicalModel::GetNumberOfBoundedParagraphRuns() 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; - } + return mBoundedParagraphRuns.Count(); +} - return *( mVisualToLogicalMap.Begin() + visualCharacterIndex ); +const Vector& LogicalModel::GetBoundedParagraphRuns() const +{ + return mBoundedParagraphRuns; } -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) { }