From: Paul Wisbey Date: Tue, 12 Apr 2016 10:37:41 +0000 (-0700) Subject: Merge changes I150e1a74,Ie6d24150,I91081f5a into devel/master X-Git-Tag: dali_1.1.30~4 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=e84f2b4052f5a042c6a08d02b87e771bac5ddf44;hp=b98287f646f84cd33e9ffc725f43a562946d13c9 Merge changes I150e1a74,Ie6d24150,I91081f5a into devel/master * changes: TextModel - Conversion from characters to glyphs. TextModel - Create paragraph info for a given range of characters inside a text. Text - Small fixes. --- diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp index 9ec9930..fa28d61 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -39,6 +40,26 @@ using namespace Text; namespace { +struct CreateParagraphData +{ + std::string description; ///< Description of the test. + std::string text; ///< Input text. + CharacterIndex index; ///< The first character index. + Length numberOfCharacters; ///< The number of characters. + unsigned int numberOfParagraphs; ///< The expected number of paragraphs. + unsigned int* indices; ///< The expected paragraph info indices. + unsigned int* numberOfCharactersPerParagraph; ///< The expected number of characters of each paragraph. +}; + +struct FindParagraphData +{ + std::string description; ///< Description of the test. + std::string text; ///< Input text. + CharacterIndex index; ///< The first character index. + Length numberOfCharacters; ///< The number of characters. + unsigned int numberOfParagraphs; ///< The expected number of paragraphs. + unsigned int* paragraphs; ///< The expected paragraph info. +}; struct SetVisualToLogicalMapData { @@ -51,6 +72,109 @@ struct SetVisualToLogicalMapData unsigned int* visualToLogical; ///< The expected visual to logical conversion table. }; +bool CreateParagraphTest( const CreateParagraphData& data ) +{ + // 1) Create the model. + LogicalModelPtr logicalModel = LogicalModel::New(); + VisualModelPtr visualModel = VisualModel::New(); + Size textArea(100.f, 60.f); + Size layoutSize; + + Vector fontDescriptionRuns; + LayoutOptions options; + CreateTextModel( data.text, + textArea, + fontDescriptionRuns, + options, + layoutSize, + logicalModel, + visualModel ); + + // 2) Clear the paragraphs. + Vector& paragraphs = logicalModel->mParagraphInfo; + ClearCharacterRuns( data.index, + data.index + data.numberOfCharacters - 1u, + paragraphs ); + + // 3) Call the LogicalModel::CreateParagraphInfo() method + logicalModel->CreateParagraphInfo( data.index, + data.numberOfCharacters ); + + // 4) Compare the results. + if( data.numberOfParagraphs != paragraphs.Count() ) + { + std::cout << " Different number of paragraphs : " << paragraphs.Count() << ", expected : " << data.numberOfParagraphs << std::endl; + return false; + } + + unsigned int index = 0u; + for( Vector::ConstIterator it = paragraphs.Begin(), + endIt = paragraphs.End(); + it != endIt; + ++it, ++index ) + { + const ParagraphRun& paragraph( *it ); + + if( data.indices[index] != paragraph.characterRun.characterIndex ) + { + std::cout << " Different character index for paragraph : " << index << ", " << paragraph.characterRun.characterIndex << ", expected : " << data.indices[index] << std::endl; + return false; + } + if( data.numberOfCharactersPerParagraph[index] != paragraph.characterRun.numberOfCharacters ) + { + std::cout << " Different number of characters for paragraph : " << index << ", " << paragraph.characterRun.numberOfCharacters << ", expected : " << data.numberOfCharactersPerParagraph[index] << std::endl; + return false; + } + } + + return true; +} + +bool FindParagraphTest( const FindParagraphData& data ) +{ + // 1) Create the model. + LogicalModelPtr logicalModel = LogicalModel::New(); + VisualModelPtr visualModel = VisualModel::New(); + Size textArea(100.f, 60.f); + Size layoutSize; + + Vector fontDescriptionRuns; + LayoutOptions options; + CreateTextModel( data.text, + textArea, + fontDescriptionRuns, + options, + layoutSize, + logicalModel, + visualModel ); + + // 2) Find the paragraphs. + Vector paragraphs; + logicalModel->FindParagraphs( data.index, data.numberOfCharacters, paragraphs ); + + // 3) compare the results. + if( data.numberOfParagraphs != paragraphs.Count() ) + { + return false; + } + + unsigned int index = 0u; + for( Vector::ConstIterator it = paragraphs.Begin(), + endIt = paragraphs.End(); + it != endIt; + ++it, ++index ) + { + const ParagraphRunIndex paragraphIndex = *it; + + if( paragraphIndex != data.paragraphs[index] ) + { + return false; + } + } + + return true; +} + bool SetVisualToLogicalMapTest( const SetVisualToLogicalMapData& data ) { std::cout << " testing : " << data.description << std::endl; @@ -106,10 +230,158 @@ bool SetVisualToLogicalMapTest( const SetVisualToLogicalMapData& data ) } // namespace ////////////////////////////////////////////////////////// +// +// UtcDaliCreateParagraph +// UtcDaliFindParagraph +// UtcDaliSetVisualToLogicalMap +// +////////////////////////////////////////////////////////// -int UtcDaliSetVisualToLogicalMap(void) +int UtcDaliCreateParagraph(void) { ToolkitTestApplication application; + tet_infoline(" UtcDaliCreateParagraph"); + + unsigned int paragraphsIndices01[] = { 0u }; + unsigned int paragraphsNumberOfCharacters01[] = { 0u }; + unsigned int paragraphsIndices02[] = { 0u, 12u, 17u }; + unsigned int paragraphsNumberOfCharacters02[] = { 12u, 5u, 1u }; + unsigned int paragraphsIndices03[] = { 0u, 12u, 17u, 34u }; + unsigned int paragraphsNumberOfCharacters03[] = { 12u, 5u, 17u ,1u }; + + struct CreateParagraphData data[] = + { + { + "Zero characters", + "", + 0u, + 0u, + 0u, + paragraphsIndices01, + paragraphsNumberOfCharacters01, + }, + { + "Some paragraphs", + "Hello world\ndemo\n\n", + 0u, + 18u, + 3u, + paragraphsIndices02, + paragraphsNumberOfCharacters02, + }, + { + "Some paragraphs. Update the initial paragraphs.", + "Hello world\ndemo\nhello world demo\n\n", + 0u, + 17u, + 4u, + paragraphsIndices03, + paragraphsNumberOfCharacters03, + }, + { + "Some paragraphs. Update the mid paragraphs.", + "Hello world\ndemo\nhello world demo\n\n", + 12u, + 5u, + 4u, + paragraphsIndices03, + paragraphsNumberOfCharacters03, + }, + { + "Some paragraphs. Update the final paragraphs.", + "Hello world\ndemo\nhello world demo\n\n", + 17u, + 18u, + 4u, + paragraphsIndices03, + paragraphsNumberOfCharacters03, + }, + }; + const unsigned int numberOfTests = 5u; + + for( unsigned int index = 0u; index < numberOfTests; ++index ) + { + // ToolkitTestApplication application; + if( !CreateParagraphTest( data[index] ) ) + { + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliFindParagraph(void) +{ + tet_infoline(" UtcDaliFindParagraph"); + + unsigned int paragraphs01[] = {}; + unsigned int paragraphs02[] = { 0u, 1u, 2u }; + unsigned int paragraphs03[] = { 0u }; + unsigned int paragraphs04[] = { 1u }; + unsigned int paragraphs05[] = { 0u, 1u, 2u }; + + struct FindParagraphData data[] = + { + { + "Zero characters", + "", + 0u, + 100u, + 0u, + paragraphs01, + }, + { + "Some paragraphs", + "Hello world\ndemo\n\n", + 0u, + 18u, + 3u, + paragraphs02 + }, + { + "Some paragraphs", + "Hello world\ndemo\n\n", + 0u, + 12u, + 1u, + paragraphs03 + }, + { + "Some paragraphs", + "Hello world\ndemo\n\n", + 12u, + 5u, + 1u, + paragraphs04 + }, + { + "Some paragraphs", + "Hello world\ndemo\n\n", + 3u, + 15u, + 3u, + paragraphs05 + }, + }; + const unsigned int numberOfTests = 5u; + + for( unsigned int index = 0u; index < numberOfTests; ++index ) + { + ToolkitTestApplication application; + if( !FindParagraphTest( data[index] ) ) + { + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliSetVisualToLogicalMap(void) +{ tet_infoline(" UtcDaliSetVisualToLogicalMap"); unsigned int* visualToLogical01 = NULL; @@ -210,6 +482,7 @@ int UtcDaliSetVisualToLogicalMap(void) for( unsigned int index = 0u; index < numberOfTests; ++index ) { + ToolkitTestApplication application; if( !SetVisualToLogicalMapTest( data[index] ) ) { tet_result(TET_FAIL); diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp index 0023240..5366164 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp @@ -62,13 +62,31 @@ bool LineBreakInfoTest( const BreakInfoData& data ) utf32.Resize( numberOfCharacters ); - // 2) Set the line break info. + // 2) Set the line break info for the whole text. Vector lineBreakInfo; lineBreakInfo.Resize( numberOfCharacters ); - SetLineBreakInfo( utf32, lineBreakInfo ); + SetLineBreakInfo( utf32, + 0u, + numberOfCharacters, + lineBreakInfo ); + + // 3) Update the word text info if it's requested for part of the text. + if( ( 0u != data.index ) && + ( numberOfCharacters != data.numberOfCharacters ) ) + { + // Clear part of the line break info. + lineBreakInfo.Erase( lineBreakInfo.Begin() + data.index, + lineBreakInfo.Begin() + data.index + data.numberOfCharacters ); - // 3) compare the results + // Update the word line info. + SetLineBreakInfo( utf32, + data.index, + data.numberOfCharacters, + lineBreakInfo ); + } + + // 4) compare the results std::ostringstream breakInfo; for( unsigned int index = 0u; index < numberOfCharacters; ++index ) @@ -78,8 +96,11 @@ bool LineBreakInfoTest( const BreakInfoData& data ) if( data.breakInfo != breakInfo.str() ) { - std::cout << " expected : [" << data.breakInfo << "]" << std::endl; - std::cout << " got : [" << breakInfo.str() << "]" << std::endl; + std::cout << " text : [" << data.text << "]" << std::endl; + std::cout << " index : " << data.index << std::endl; + std::cout << " numberOfCharacters : " << data.numberOfCharacters << std::endl; + std::cout << " expected : [" << data.breakInfo << "]" << std::endl; + std::cout << " got : [" << breakInfo.str() << "]" << std::endl; return false; } @@ -149,7 +170,6 @@ bool WordBreakInfoTest( const BreakInfoData& data ) int UtcDaliTextSegnemtationSetLineBreakInfo(void) { - ToolkitTestApplication application; tet_infoline(" UtcDaliTextSegnemtationSetLineBreakInfo"); struct BreakInfoData data[] = @@ -177,6 +197,51 @@ int UtcDaliTextSegnemtationSetLineBreakInfo(void) "222222122222221221222212212221222222122222222220", }, { + "Latin script. Update initial paragraphs.", + "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n" + "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n" + "Ne nec nulla regione albucius, mea doctus delenit ad!\n" + "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n" + "Quidam corpora at duo. An eos possim scripserit?", + 0u, + 141u, + "22222122222122222122212222212222212222222222122122221222221222222222122122220" + "2221221222212222222122222222221222222122222222122222222122212220" + "221222122222122222221222222222122212222221222222212220" + "22122222212222222122222222222122221222122222122222222222122222222222212220" + "222222122222221221222212212221222222122222222220", + }, + { + "Latin script. Update mid paragraphs.", + "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n" + "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n" + "Ne nec nulla regione albucius, mea doctus delenit ad!\n" + "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n" + "Quidam corpora at duo. An eos possim scripserit?", + 141u, + 128u, + "22222122222122222122212222212222212222222222122122221222221222222222122122220" + "2221221222212222222122222222221222222122222222122222222122212220" + "221222122222122222221222222222122212222221222222212220" + "22122222212222222122222222222122221222122222122222222222122222222222212220" + "222222122222221221222212212221222222122222222220", + }, + { + "Latin script. Update final paragraphs.", + "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n" + "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n" + "Ne nec nulla regione albucius, mea doctus delenit ad!\n" + "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n" + "Quidam corpora at duo. An eos possim scripserit?", + 195u, + 122u, + "22222122222122222122212222212222212222222222122122221222221222222222122122220" + "2221221222212222222122222222221222222122222222122222222122212220" + "221222122222122222221222222222122212222221222222212220" + "22122222212222222122222222222122221222122222122222222222122222222222212220" + "222222122222221221222212212221222222122222222220", + }, + { "Japanese script", "韓国側は北朝鮮当局を通じて米ドルで賃金を支払う。\n" "国際社会から様々な経済制裁を受ける北朝鮮にとっては出稼ぎ労働などと並んで重要な外貨稼ぎの手段となっている。\n" @@ -199,10 +264,11 @@ int UtcDaliTextSegnemtationSetLineBreakInfo(void) "21111112112111111111111211121111111111120", } }; - const unsigned int numberOfTests = 4u; + const unsigned int numberOfTests = 7u; for( unsigned int index = 0u; index < numberOfTests; ++index ) { + ToolkitTestApplication application; if( !LineBreakInfoTest( data[index] ) ) { tet_result(TET_FAIL); @@ -215,7 +281,6 @@ int UtcDaliTextSegnemtationSetLineBreakInfo(void) int UtcDaliTextSegnemtationSetWordBreakInfo(void) { - ToolkitTestApplication application; tet_infoline(" UtcDaliTextSegnemtationSetWordBreakInfo"); struct BreakInfoData data[] = @@ -380,6 +445,7 @@ int UtcDaliTextSegnemtationSetWordBreakInfo(void) for( unsigned int index = 0u; index < numberOfTests; ++index ) { + ToolkitTestApplication application; if( !WordBreakInfoTest( data[index] ) ) { tet_result(TET_FAIL); diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp index fdde254..fe6d4cb 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp @@ -84,10 +84,12 @@ bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data ) Vector& charactersToGlyph = visualModel->mCharactersToGlyph; Vector& glyphsPerCharacter = visualModel->mGlyphsPerCharacter; + GlyphIndex startGlyphIndex = 0u; if( 0u != charactersToGlyph.Count() ) { // The number of glyphs to be removed. const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex]; + startGlyphIndex = charactersToGlyph[data.startIndex]; charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex, charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters ); @@ -106,6 +108,7 @@ bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data ) // 3) Call the CreateGlyphsPerCharacterTable() function visualModel->CreateGlyphsPerCharacterTable( data.startIndex, + startGlyphIndex, data.numberOfCharacters ); // 4) Compare the results. @@ -160,10 +163,12 @@ bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data ) Vector& charactersToGlyph = visualModel->mCharactersToGlyph; Vector& glyphsPerCharacter = visualModel->mGlyphsPerCharacter; + GlyphIndex startGlyphIndex = 0u; if( 0u != charactersToGlyph.Count() ) { // The number of glyphs to be removed. const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex]; + startGlyphIndex = charactersToGlyph[data.startIndex]; charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex, charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters ); @@ -180,6 +185,7 @@ bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data ) // 3) Call the CreateCharacterToGlyphTable() function visualModel->CreateCharacterToGlyphTable( data.startIndex, + startGlyphIndex, data.numberOfCharacters ); // 4) Compare the results. diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp index 5bde6be..aff7eb7 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp @@ -116,7 +116,10 @@ void CreateTextModel( const std::string& text, Vector& lineBreakInfo = logicalModel->mLineBreakInfo; lineBreakInfo.Resize( numberOfCharacters ); - SetLineBreakInfo( utf32Characters, lineBreakInfo ); + SetLineBreakInfo( utf32Characters, + 0u, + numberOfCharacters, + lineBreakInfo ); if( 0u == numberOfCharacters ) { @@ -184,6 +187,10 @@ void CreateTextModel( const std::string& text, numberOfCharacters, bidirectionalInfo ); + // Create the paragraph info. + logicalModel->CreateParagraphInfo( 0u, + numberOfCharacters ); + // 6) Set character directions. Vector& characterDirections = logicalModel->mCharacterDirections; if( 0u != bidirectionalInfo.Count() ) @@ -232,8 +239,8 @@ void CreateTextModel( const std::string& text, newParagraphGlyphs ); // Create the 'number of glyphs' per character and the glyph to character conversion tables. - visualModel->CreateGlyphsPerCharacterTable( 0u, numberOfCharacters ); - visualModel->CreateCharacterToGlyphTable( 0u, numberOfCharacters ); + visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters ); + visualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters ); const Length numberOfGlyphs = glyphs.Count(); diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp index 8af3e91..239a2f8 100644 --- a/dali-toolkit/internal/text/logical-model-impl.cpp +++ b/dali-toolkit/internal/text/logical-model-impl.cpp @@ -420,6 +420,131 @@ 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 ); + } + } +} + LogicalModel::~LogicalModel() { ClearFontDescriptionRuns(); diff --git a/dali-toolkit/internal/text/logical-model-impl.h b/dali-toolkit/internal/text/logical-model-impl.h index 7085d79..e41f0fa 100644 --- a/dali-toolkit/internal/text/logical-model-impl.h +++ b/dali-toolkit/internal/text/logical-model-impl.h @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace Dali @@ -136,6 +137,30 @@ public: */ void ClearFontDescriptionRuns(); + // Paragraphs + + /** + * @brief Creates the paragraph info. + * + * @pre The line break info must be set. + * + * @param[in] startIndex The character from where the paragraph info is set. + * @param[in] numberOfCharacters The number of characters. + */ + void CreateParagraphInfo( CharacterIndex startIndex, + Length numberOfCharacters ); + + /** + * @brief Find the paragraphs which contains the given characters. + * + * @param[in] index The first character's index of the run. + * @param[in] numberOfCharacters The number of characters of the run. + * @param[out] paragraphs Indices to the paragraphs which contain the characters. + */ + void FindParagraphs( CharacterIndex index, + Length numberOfCharacters, + Vector& paragraphs ); + protected: /** @@ -165,6 +190,7 @@ public: Vector mFontDescriptionRuns; Vector mLineBreakInfo; Vector mWordBreakInfo; + Vector mParagraphInfo; Vector mBidirectionalParagraphInfo; Vector mCharacterDirections; ///< For each character, whether is right to left. ( @e flase is left to right, @e true right to left ). Vector mBidirectionalLineInfo; diff --git a/dali-toolkit/internal/text/paragraph-run.h b/dali-toolkit/internal/text/paragraph-run.h new file mode 100644 index 0000000..7a90363 --- /dev/null +++ b/dali-toolkit/internal/text/paragraph-run.h @@ -0,0 +1,54 @@ +#ifndef __DALI_TOOLKIT_TEXT_PARAGRAPH_RUN_H__ +#define __DALI_TOOLKIT_TEXT_PARAGRAPH_RUN_H__ + +/* + * Copyright (c) 2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +/** + * @brief ParagraphRun + * + * In terms of the bidirectional algorithm, a 'paragraph' is understood as a run of characters between Paragraph Separators or appropriate Newline Functions. + * A 'paragraph' may also be determined by higher-level protocols like a mark-up tag. + */ +struct ParagraphRun +{ + CharacterRun characterRun; ///< The initial character index within the whole text and the number of characters of the run. + Size layoutSize; ///< The size of the paragraph when is laid-out. +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_PARAGRAPH_RUN_H__ diff --git a/dali-toolkit/internal/text/segmentation.cpp b/dali-toolkit/internal/text/segmentation.cpp index 5e590b5..61afef1 100644 --- a/dali-toolkit/internal/text/segmentation.cpp +++ b/dali-toolkit/internal/text/segmentation.cpp @@ -50,21 +50,51 @@ namespace Text { void SetLineBreakInfo( const Vector& text, + CharacterIndex startIndex, + Length numberOfCharacters, Vector& lineBreakInfo ) { - const Length numberOfCharacters = text.Count(); + const Length totalNumberOfCharacters = text.Count(); - if( 0u == numberOfCharacters ) + if( 0u == totalNumberOfCharacters ) { // Nothing to do if there are no characters. return; } // Retrieve the line break info. - lineBreakInfo.Resize( numberOfCharacters ); - TextAbstraction::Segmentation::Get().GetLineBreakPositions( text.Begin(), + lineBreakInfo.Resize( totalNumberOfCharacters ); + + // Whether the current buffer is being updated or is set from scratch. + const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters; + + LineBreakInfo* lineBreakInfoBuffer = NULL; + Vector newLineBreakInfo; + + if( updateCurrentBuffer ) + { + newLineBreakInfo.Resize( numberOfCharacters ); + lineBreakInfoBuffer = newLineBreakInfo.Begin(); + } + else + { + lineBreakInfoBuffer = lineBreakInfo.Begin(); + } + + // Retrieve the line break info. + TextAbstraction::Segmentation::Get().GetLineBreakPositions( text.Begin() + startIndex, numberOfCharacters, - lineBreakInfo.Begin() ); + lineBreakInfoBuffer ); + + // If the line break info is updated, it needs to be inserted in the model. + if( updateCurrentBuffer ) + { + lineBreakInfo.Insert( lineBreakInfo.Begin() + startIndex, + newLineBreakInfo.Begin(), + newLineBreakInfo.End() ); + lineBreakInfo.Resize( totalNumberOfCharacters ); + } + #ifdef DEBUG_ENABLED if( gLogFilter->IsEnabledFor(Debug::Verbose) ) { diff --git a/dali-toolkit/internal/text/segmentation.h b/dali-toolkit/internal/text/segmentation.h index 61ddcc7..e23065a 100644 --- a/dali-toolkit/internal/text/segmentation.h +++ b/dali-toolkit/internal/text/segmentation.h @@ -45,9 +45,13 @@ class LogicalModel; * - 2 is a LINE_NO_BREAK. Text can't be broken into a new line. * * @param[in] text Vector of UTF-32 characters. + * @param[in] startIndex The character from where the break info is set. + * @param[in] numberOfCharacters The number of characters. * @param[out] lineBreakInfo The line break info */ void SetLineBreakInfo( const Vector& text, + CharacterIndex startIndex, + Length numberOfCharacters, Vector& lineBreakInfo ); /** diff --git a/dali-toolkit/internal/text/shaper.cpp b/dali-toolkit/internal/text/shaper.cpp index 5313d0c..cd0b1d7 100644 --- a/dali-toolkit/internal/text/shaper.cpp +++ b/dali-toolkit/internal/text/shaper.cpp @@ -175,7 +175,7 @@ void ShapeText( const Vector& text, shaping.GetGlyphs( tmpGlyphs.Begin(), tmpGlyphToCharacterMap.Begin() ); - // Update the indices. + // Update the new indices of the glyph to character map. if( 0u != totalNumberOfGlyphs ) { for( Vector::Iterator it = tmpGlyphToCharacterMap.Begin(), diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index d681730..5571f94 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -336,7 +336,13 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK ); SetLineBreakInfo( utf32Characters, + startIndex, + requestedNumberOfCharacters, lineBreakInfo ); + + // Create the paragraph info. + mLogicalModel->CreateParagraphInfo( startIndex, + requestedNumberOfCharacters ); } Vector& wordBreakInfo = mLogicalModel->mWordBreakInfo; @@ -471,8 +477,8 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) newParagraphGlyphs ); // Create the 'number of glyphs' per character and the glyph to character conversion tables. - mVisualModel->CreateGlyphsPerCharacterTable( startIndex, numberOfCharacters ); - mVisualModel->CreateCharacterToGlyphTable( startIndex, numberOfCharacters ); + mVisualModel->CreateGlyphsPerCharacterTable( startIndex, startGlyphIndex, numberOfCharacters ); + mVisualModel->CreateCharacterToGlyphTable( startIndex, startGlyphIndex, numberOfCharacters ); } const Length numberOfGlyphs = glyphs.Count(); diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 153a36c..ab41790 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -466,7 +466,7 @@ float Controller::GetDefaultPointSize() const return 0.0f; } -void Controller::UpdateAfterFontChange( std::string& newDefaultFont ) +void Controller::UpdateAfterFontChange( const std::string& newDefaultFont ) { DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange"); @@ -499,7 +499,7 @@ const Vector4& Controller::GetTextColor() const return mImpl->mTextColor; } -bool Controller::RemoveText( int cursorOffset, int numberOfChars ) +bool Controller::RemoveText( int cursorOffset, int numberOfCharacters ) { bool removed = false; @@ -508,8 +508,8 @@ bool Controller::RemoveText( int cursorOffset, int numberOfChars ) return removed; } - DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfChars %d\n", - this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfChars ); + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n", + this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters ); if( !mImpl->IsShowingPlaceholderText() ) { @@ -525,12 +525,12 @@ bool Controller::RemoveText( int cursorOffset, int numberOfChars ) cursorIndex = oldCursorIndex + cursorOffset; } - if( ( cursorIndex + numberOfChars ) > currentText.Count() ) + if( ( cursorIndex + numberOfCharacters ) > currentText.Count() ) { - numberOfChars = currentText.Count() - cursorIndex; + numberOfCharacters = currentText.Count() - cursorIndex; } - if( ( cursorIndex + numberOfChars ) <= currentText.Count() ) + if( ( cursorIndex + numberOfCharacters ) <= currentText.Count() ) { // Update the input style and remove the text's style before removing the text. @@ -541,18 +541,18 @@ bool Controller::RemoveText( int cursorOffset, int numberOfChars ) mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle ); // Remove the text's style before removing the text. - mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfChars ); + mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters ); // Remove the characters. Vector::Iterator first = currentText.Begin() + cursorIndex; - Vector::Iterator last = first + numberOfChars; + Vector::Iterator last = first + numberOfCharacters; currentText.Erase( first, last ); // Cursor position retreat oldCursorIndex = cursorIndex; - DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfChars ); + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters ); removed = true; } } @@ -1776,14 +1776,14 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ // Remove the previous IMF pre-edit (predicitive text) if( mImpl->mEventData->mPreEditFlag && - ( 0 != mImpl->mEventData->mPreEditLength ) ) + ( 0u != mImpl->mEventData->mPreEditLength ) ) { - CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition; + const CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition; - removedPrevious = RemoveText( -static_cast(offset), mImpl->mEventData->mPreEditLength ); + removedPrevious = RemoveText( -static_cast( offset ), mImpl->mEventData->mPreEditLength ); mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition; - mImpl->mEventData->mPreEditLength = 0; + mImpl->mEventData->mPreEditLength = 0u; } else { @@ -1842,7 +1842,7 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count(); - // Restrict new text to fit within Maximum characters setting + // Restrict new text to fit within Maximum characters setting. Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount ); maxLengthReached = ( characterCount > maxSizeOfNewText ); @@ -2514,7 +2514,7 @@ void Controller::ShowPlaceholderText() // Transform a text array encoded in utf8 into an array encoded in utf32. // It returns the actual number of characters. - Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() ); + const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() ); utf32Characters.Resize( characterCount ); // Reset the cursor position diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index d239d13..7e22134 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -151,10 +151,10 @@ public: * @brief Remove a given number of characters * * @param[in] cursorOffset Start position from the current cursor position to start deleting characters. - * @param[in] numberOfChars The number of characters to delete from the cursorOffset. + * @param[in] numberOfCharacters The number of characters to delete from the cursorOffset. * @return True if the remove was successful. */ - bool RemoveText( int cursorOffset, int numberOfChars ); + bool RemoveText( int cursorOffset, int numberOfCharacters ); /** * @brief Retrieve the current cursor position. @@ -283,7 +283,7 @@ public: * @ brief Update the text after a font change * @param[in] newDefaultFont The new font to change to */ - void UpdateAfterFontChange( std::string& newDefaultFont ); + void UpdateAfterFontChange( const std::string& newDefaultFont ); /** * @brief Set the text color diff --git a/dali-toolkit/internal/text/text-definitions.h b/dali-toolkit/internal/text/text-definitions.h index 4879090..0e9fb3f 100644 --- a/dali-toolkit/internal/text/text-definitions.h +++ b/dali-toolkit/internal/text/text-definitions.h @@ -59,6 +59,7 @@ typedef uint32_t UnderlineRunIndex; ///< An inde typedef uint32_t BidirectionalRunIndex; ///< An index into an array of bidirectional info. typedef uint32_t BidirectionalLineRunIndex; ///< An index into an array of bidirectional line info. typedef uint32_t LineIndex; ///< An index into an array of lines. +typedef uint32_t ParagraphRunIndex; ///< An index into an array of paragraphs. } // namespace Text diff --git a/dali-toolkit/internal/text/text-run-container.h b/dali-toolkit/internal/text/text-run-container.h index 37d7b00..ecac39d 100644 --- a/dali-toolkit/internal/text/text-run-container.h +++ b/dali-toolkit/internal/text/text-run-container.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__ -#define __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__ +#ifndef __DALI_TOOLKIT_TEXT_RUN_CONTAINER_H__ +#define __DALI_TOOLKIT_TEXT_RUN_CONTAINER_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -300,6 +300,7 @@ void ClearGlyphRuns( GlyphIndex startIndex, ( startIndex >= run->glyphRun.glyphIndex + run->glyphRun.numberOfGlyphs ) ) { // Run found. Nothing else to do. + break; } ++run; @@ -352,4 +353,4 @@ void ClearGlyphRuns( GlyphIndex startIndex, } // namespace Dali -#endif // __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__ +#endif // __DALI_TOOLKIT_TEXT_RUN_CONTAINER_H__ diff --git a/dali-toolkit/internal/text/visual-model-impl.cpp b/dali-toolkit/internal/text/visual-model-impl.cpp index 138ce54..c1faee7 100644 --- a/dali-toolkit/internal/text/visual-model-impl.cpp +++ b/dali-toolkit/internal/text/visual-model-impl.cpp @@ -36,6 +36,7 @@ VisualModelPtr VisualModel::New() } void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex, + GlyphIndex startGlyphIndex, Length numberOfCharacters ) { if( 0u == numberOfCharacters ) @@ -72,7 +73,6 @@ void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex, // 2) Traverse the glyphs and set the glyph indices per character. // Index to the glyph. - const GlyphIndex startGlyphIndex = updateCurrentBuffer ? *( mCharactersToGlyph.Begin() + startIndex ) : 0u; GlyphIndex glyphIndex = startGlyphIndex; CharacterIndex characterIndex = startIndex; const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters; @@ -115,6 +115,7 @@ void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex, } void VisualModel::CreateGlyphsPerCharacterTable( CharacterIndex startIndex, + GlyphIndex startGlyphIndex, Length numberOfCharacters ) { if( 0u == numberOfCharacters ) @@ -146,14 +147,12 @@ void VisualModel::CreateGlyphsPerCharacterTable( CharacterIndex startIndex, // 2) Traverse the glyphs and set the number of glyphs per character. - // The glyph index. - const GlyphIndex glyphIndex = updateCurrentBuffer ? *( mCharactersToGlyph.Begin() + startIndex ) : 0u; Length traversedCharacters = 0; // The number of 'characters per glyph' equal to zero. Length zeroCharactersPerGlyph = 0u; - for( Vector::ConstIterator it = mCharactersPerGlyph.Begin() + glyphIndex, + for( Vector::ConstIterator it = mCharactersPerGlyph.Begin() + startGlyphIndex, endIt = mCharactersPerGlyph.End(); ( it != endIt ) && ( traversedCharacters < numberOfCharacters ); ++it ) diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h index a0339a4..5aa90af 100644 --- a/dali-toolkit/internal/text/visual-model-impl.h +++ b/dali-toolkit/internal/text/visual-model-impl.h @@ -67,18 +67,22 @@ public: * @pre The glyphs per character table needs to be created first. * * @param[in] startIndex The character from where the conversion table is created. + * @param[in] startGlyphIndex The glyph from where the conversion table is created. * @param[in] numberOfCharacters The number of characters. */ void CreateCharacterToGlyphTable( CharacterIndex startIndex, + GlyphIndex startGlyphIndex, Length numberOfCharacters ); /** * @brief Creates an array containing the number of glyphs per character. * * @param[in] startIndex The character from where the table is created. + * @param[in] startGlyphIndex The glyph from where the conversion table is created. * @param[in] numberOfCharacters The number of characters. */ void CreateGlyphsPerCharacterTable( CharacterIndex startIndex, + GlyphIndex startGlyphIndex, Length numberOfCharacters ); /**