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=66c6d8933efbc37daff2661d39eebd5d5458cb9b;hp=10b2a49a8a464dc33c870988fa89c189380e9fdb;hb=204a8ff506d634e38af6838009f55fa5e07118fe;hpb=49fabc565606e00c95baacb41f009de2a532a4da diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp old mode 100644 new mode 100755 index 10b2a49..66c6d89 --- 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) 2019 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. @@ -20,7 +20,7 @@ // INTERNAL INCLUDES #include -#include +#include namespace Dali { @@ -31,6 +31,33 @@ namespace Toolkit namespace Text { +void FreeFontFamilyNames( Vector& fontDescriptionRuns ) +{ + for( Vector::Iterator it = fontDescriptionRuns.Begin(), + endIt = fontDescriptionRuns.End(); + it != endIt; + ++it ) + { + delete[] (*it).familyName; + } + + fontDescriptionRuns.Clear(); +} + +void FreeEmbeddedItems( Vector& embeddedItem ) +{ + for( Vector::Iterator it = embeddedItem.Begin(), + endIt = embeddedItem.End(); + it != endIt; + ++it ) + { + EmbeddedItem& item = *it; + delete[] item.url; + } + + embeddedItem.Clear(); +} + LogicalModelPtr LogicalModel::New() { return LogicalModelPtr( new LogicalModel() ); @@ -40,9 +67,10 @@ Script LogicalModel::GetScript( CharacterIndex characterIndex ) const { // 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 ) { - 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 ) ) @@ -65,184 +93,188 @@ CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex character return *( mCharacterDirections.Begin() + characterIndex ); } -void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo, - Length numberOfRuns ) +CharacterIndex LogicalModel::GetLogicalCursorIndex( CharacterIndex visualCursorIndex ) { - if( 0u == numberOfRuns ) - { - mVisualToLogicalMap.Clear(); - mLogicalToVisualMap.Clear(); - mVisualToLogicalCursorMap.Clear(); - } - else - { - const Length numberOfCharacters = mText.Count(); - mVisualToLogicalMap.Resize( numberOfCharacters ); - mLogicalToVisualMap.Resize( numberOfCharacters ); - - const Length numberOfCharactersPlus = numberOfCharacters + 1u; - mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus ); + // The character's directions buffer. + const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin(); - CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin(); - CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin(); + // The bidirectional line info. + const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex; - CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin(); + // Whether the paragraph starts with a right to left character. + const bool isRightToLeftParagraph = bidirectionalLineInfo->direction; - CharacterIndex lastIndex = 0u; - for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex ) - { - const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex ); + // The total number of characters of the line. + const Length lastCharacterIndex = bidirectionalLineInfo->characterRun.characterIndex + bidirectionalLineInfo->characterRun.numberOfCharacters; - if( lastIndex < bidiLineInfo.characterRun.characterIndex ) - { - // Fill with the identity. - for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex ) - { - *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex; - } - } + CharacterIndex logicalCursorIndex = 0u; - // 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 ); - } + if( bidirectionalLineInfo->characterRun.characterIndex == visualCursorIndex ) + { + if( isRightToLeftParagraph ) + { + logicalCursorIndex = lastCharacterIndex; } - - // Complete with the identity if there are some left to right characters after the last right to left. - for( ; lastIndex < numberOfCharacters; ++lastIndex ) + else // else logical position is the first of the line. { - *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex; + logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex; } - - // Sets the logical to visual conversion map. - for( CharacterIndex index = 0u; index < numberOfCharacters; ++index ) + } + else if( lastCharacterIndex == visualCursorIndex ) + { + if( isRightToLeftParagraph ) { - *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index; + logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex; } + else // else logical position is the number of characters. + { + logicalCursorIndex = lastCharacterIndex; + } + } + 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. - // Sets the visual to logical conversion map for cursor positions. - - const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count(); - BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin(); - BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer; + 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; - const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin(); + const CharacterDirection previousCharacterDirection = *( modelCharacterDirections + previousLogicalCursorIndex ); + const CharacterDirection currentCharacterDirection = *( modelCharacterDirections + currentLogicalCursorIndex ); - Length bidirectionalParagraphIndex = 0u; - bool isRightToLeftParagraph = false; - for( CharacterIndex index = 0u; index < numberOfCharactersPlus; ++index ) + if( previousCharacterDirection == currentCharacterDirection ) { - if( bidirectionalParagraph && - ( bidirectionalParagraph->characterRun.characterIndex == index ) ) + // Both glyphs have the same direction. + if( previousCharacterDirection ) { - isRightToLeftParagraph = *( modelCharacterDirections + index ); + logicalCursorIndex = previousLogicalCursorIndex; } - - if( 0u == index ) + else { - if( isRightToLeftParagraph ) - { - *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters; - } - else // else logical position is zero. - { - *( modelVisualToLogicalCursorMap + index ) = 0u; - } + logicalCursorIndex = currentLogicalCursorIndex; } - else if( numberOfCharacters == index ) + } + else + { + if( isRightToLeftParagraph ) { - if( isRightToLeftParagraph ) + if( currentCharacterDirection ) { - *( modelVisualToLogicalCursorMap + index ) = 0u; + logicalCursorIndex = currentLogicalCursorIndex + 1u; } - else // else logical position is the number of characters. + else { - *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters; + logicalCursorIndex = previousLogicalCursorIndex; } } 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 ) + if( previousCharacterDirection ) { - // Both glyphs have the same direction. - if( direction0 ) - { - *( modelVisualToLogicalCursorMap + index ) = logicalPosition0; - } - else - { - *( modelVisualToLogicalCursorMap + index ) = logicalPosition1; - } + logicalCursorIndex = currentLogicalCursorIndex; } else { - if( isRightToLeftParagraph ) - { - if( direction1 ) - { - *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u; - } - else - { - *( modelVisualToLogicalCursorMap + index ) = logicalPosition0; - } - } - else - { - if( direction0 ) - { - *( modelVisualToLogicalCursorMap + index ) = logicalPosition1; - } - else - { - *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u; - } - } + logicalCursorIndex = previousLogicalCursorIndex + 1u; } } + } + } + + return logicalCursorIndex; +} + +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; +} + +bool LogicalModel::FetchBidirectionalLineInfo( CharacterIndex characterIndex ) +{ + // The number of bidirectional lines. + const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count(); + + if( 0u == numberOfBidirectionalLines ) + { + // If there is no bidirectional info. + return false; + } + + // 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 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( bidirectionalParagraph && - ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) ) + if( characterIndex < bidiLineRun.characterRun.characterIndex ) { - isRightToLeftParagraph = false; - ++bidirectionalParagraphIndex; - if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs ) - { - bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex; - } - else - { - bidirectionalParagraph = NULL; - } + // Start the fetch from the beginning. + bidiLineIndex = 0u; + } + else + { + // Start the fetch from the next line. + bidiLineIndex = mBidirectionalLineIndex + 1u; + lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u; } } } -} -CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const -{ - if( 0u == mVisualToLogicalMap.Count() ) + // 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 ) { - // If there is no visual to logical info is because the whole text is left to right. - // Return the identity. - return visualCharacterIndex; + 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; + } } - return *( mVisualToLogicalMap.Begin() + visualCharacterIndex ); + return false; +} + +BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const +{ + return mBidirectionalLineIndex; } void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters ) @@ -256,16 +288,28 @@ void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharac totalNumberOfCharacters, mColorRuns, removedColorRuns ); + + // Process the font description runs. + Vector removedFontDescriptionRuns; + UpdateCharacterRuns( 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; - unsigned int lastRunIndex = 0u; - bool overriden = false; // Set the text color. - for( Vector::ConstIterator it = mColorRuns.Begin(), + 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 ) @@ -275,26 +319,264 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style ) if( ( colorRun.characterRun.characterIndex <= index ) && ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) ) { - lastRunIndex = runIndex; - overriden = true; + colorIndex = runIndex; + colorOverriden = true; } } // Set the text's color if it's overriden. - if( overriden ) + if( colorOverriden ) { - style.textColor = ( *( mColorRuns.Begin() + lastRunIndex ) ).color; + style.textColor = ( *( colorRunsBuffer + colorIndex ) ).color; + style.isDefaultColor = false; } + // Reset the run index. runIndex = 0u; - overriden = false; + + // 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 ) + { + 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.isFamilyDefined = true; + } + + // Set the font's weight if it's overriden. + if( weightOverriden ) + { + const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + weightIndex ); + + style.weight = fontDescriptionRun.weight; + style.isWeightDefined = true; + } + + // Set the font's width if it's overriden. + if( widthOverriden ) + { + const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + widthIndex ); + + style.width = fontDescriptionRun.width; + style.isWidthDefined = true; + } + + // Set the font's slant if it's overriden. + if( slantOverriden ) + { + const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + slantIndex ); + + style.slant = fontDescriptionRun.slant; + style.isSlantDefined = true; + } + + // Set the font's size if it's overriden. + if( sizeOverriden ) + { + const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + sizeIndex ); + + style.size = static_cast( fontDescriptionRun.size ) / 64.f; + style.isSizeDefined = true; + } +} + +void LogicalModel::ClearFontDescriptionRuns() +{ + FreeFontFamilyNames( mFontDescriptionRuns ); +} + +void LogicalModel::CreateParagraphInfo( CharacterIndex startIndex, + Length numberOfCharacters ) +{ + const Length totalNumberOfCharacters = mLineBreakInfo.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 ) + { + if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) ) + { + paragraphs.PushBack( index ); + } + } + + // Whether the current paragraphs are updated or set from scratch. + const bool updateCurrentParagraphs = numberOfCharacters < totalNumberOfCharacters; + + // 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 newParagraphs; + + if( updateCurrentParagraphs ) + { + newParagraphs.Resize( numberOfNewParagraphs ); + paragraphInfoBuffer = newParagraphs.Begin(); + } + else + { + paragraphInfoBuffer = mParagraphInfo.Begin(); + } + + // Find where to insert the new paragraphs. + ParagraphRunIndex paragraphIndex = 0u; + CharacterIndex firstIndex = startIndex; + + if( updateCurrentParagraphs ) + { + for( Vector::ConstIterator it = mParagraphInfo.Begin(), + endIt = mParagraphInfo.Begin() + totalNumberOfParagraphs - numberOfNewParagraphs; + it != endIt; + ++it ) + { + const ParagraphRun& paragraph( *it ); + + if( startIndex < paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters ) + { + firstIndex = paragraph.characterRun.characterIndex; + break; + } + + ++paragraphIndex; + } + } + + // 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() ); + + mParagraphInfo.Resize( totalNumberOfParagraphs ); + + // Update the next paragraph indices. + for( Vector::Iterator it = mParagraphInfo.Begin() + paragraphIndex + newParagraphs.Count(), + endIt = mParagraphInfo.End(); + it != endIt; + ++it ) + { + ParagraphRun& paragraph( *it ); + + paragraph.characterRun.characterIndex += numberOfCharacters; + } + } +} + +void LogicalModel::FindParagraphs( CharacterIndex index, + Length numberOfCharacters, + Vector& paragraphs ) +{ + // Reserve som space for the paragraph indices. + paragraphs.Reserve( mParagraphInfo.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 ) + { + const ParagraphRun& paragraph( *it ); + + if( ( paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters > index ) && + ( paragraph.characterRun.characterIndex < index + numberOfCharacters ) ) + { + paragraphs.PushBack( paragraphIndex ); + } + } +} + +void LogicalModel::ClearEmbeddedImages() +{ + FreeEmbeddedItems( mEmbeddedItems ); } LogicalModel::~LogicalModel() { + ClearFontDescriptionRuns(); + ClearEmbeddedImages(); } LogicalModel::LogicalModel() +: mBidirectionalLineIndex( 0u ) { }