utc-Dali-Text-CharacterSetConversion.cpp
utc-Dali-Text-Segmentation.cpp
utc-Dali-Text-MultiLanguage.cpp
+ utc-Dali-LogicalModel.cpp
+ utc-Dali-BidirectionalSupport.cpp
)
# Append list of test harness files (Won't get parsed for test cases)
../dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.cpp
../dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp
../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp
../dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
../dali-toolkit/dali-toolkit-test-utils/test-application.cpp
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+
+#include <dali/devel-api/text-abstraction/bidirectional-support.h>
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-model.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions.
+//
+// void SetBidirectionalInfo( const Vector<Character>& text,
+// const Vector<ScriptRun>& scripts,
+// const Vector<LineBreakInfo>& lineBreakInfo,
+// CharacterIndex startIndex,
+// Length numberOfCharacters,
+// Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
+// void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+// CharacterIndex startIndex,
+// Length numberOfCharacters,
+// Vector<LineRun>& lineRuns,
+// Vector<BidirectionalLineInfoRun>& lineInfoRuns )
+// bool GetMirroredText( const Vector<Character>& text,
+// Vector<CharacterDirection>& directions,
+// const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+// CharacterIndex startIndex,
+// Length numberOfCharacters,
+// Vector<Character>& mirroredText )
+// void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+// CharacterIndex startIndex,
+// Length numberOfCharacters,
+// Vector<CharacterDirection>& directions )
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct SetBidirectionalInfoData
+{
+ std::string description; ///< Description of the test.
+ std::string text; ///< Input text.
+ unsigned int startIndex; ///< The index from where the model is updated.
+ unsigned int numberOfCharacters; ///< The number of characters to update.
+ unsigned int numberOfParagraphs; ///< The expected number of bidirectional paragraphs.
+ unsigned int* indices; ///< The expected indices to the first character of each paragraph.
+ unsigned int* numberOfParagraphCharacters; ///< The expected number of characters of each paragraph.
+ bool* directions; ///< The expected direction of each paragraph.
+};
+
+struct BidiLineData
+{
+ unsigned int characterIndex;
+ unsigned int numberOfCharacters;
+ unsigned int* visualToLogical;
+};
+
+struct ReorderLinesData
+{
+ std::string description; ///< Description of the test.
+ std::string text; ///< Input text.
+ unsigned int startIndex; ///< The index from where the model is updated.
+ unsigned int numberOfCharacters; ///< The number of characters.
+ unsigned int numberOfLineInfo; ///< The number or reordered lines.
+ BidiLineData* bidiLineData; ///< The bidirectional line info.
+};
+
+struct GetMirroredTextData
+{
+ std::string description; ///< Description of the test.
+ std::string text; ///< Input text.
+ unsigned int startIndex; ///< The index from where the model is updated.
+ unsigned int numberOfCharacters; ///< The number of the characters.
+ std::string mirroredText; ///< The expected result.
+};
+
+struct GetCharactersDirectionData
+{
+ std::string description; ///< Description of the test.
+ std::string text; ///< Input text.
+ unsigned int startIndex; ///< The index from where the model is updated.
+ unsigned int numberOfCharacters; ///< The number of characters.
+ bool* directions; ///< The expected directions.
+};
+
+bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
+{
+ // 1) Create the model.
+ LogicalModelPtr logicalModel = LogicalModel::New();
+ VisualModelPtr visualModel = VisualModel::New();
+ Size textArea(100.f, 60.f);
+ Size layoutSize;
+
+ // Create the model.
+ CreateTextModel( data.text,
+ textArea,
+ layoutSize,
+ logicalModel,
+ visualModel );
+
+ // 2) Clear the bidirectional paragraph info data.
+ Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+ if( 0u != data.numberOfCharacters )
+ {
+ ClearCharacterRuns( data.startIndex,
+ data.startIndex + data.numberOfCharacters - 1u,
+ bidirectionalInfo );
+ }
+
+ // 3) Call the SetBidirectionalInfo() function.
+ SetBidirectionalInfo( logicalModel->mText,
+ logicalModel->mScriptRuns,
+ logicalModel->mLineBreakInfo,
+ data.startIndex,
+ data.numberOfCharacters,
+ bidirectionalInfo );
+
+ // 4) Compare with the expected results.
+ TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+ if( data.numberOfParagraphs != bidirectionalInfo.Count() )
+ {
+ // Different number of expected bidirectional paragraphs.
+ std::cout << " Different number of bidi paragraphs : " << bidirectionalInfo.Count() << ", expected : " << data.numberOfParagraphs << std::endl;
+ return false;
+ }
+
+ for( unsigned int index = 0u; index < data.numberOfParagraphs; ++index )
+ {
+ const BidirectionalParagraphInfoRun& run = bidirectionalInfo[index];
+
+ const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( run.bidirectionalInfoIndex );
+ if( direction != data.directions[index] )
+ {
+ std::cout << " Different direction" << std::endl;
+ std::cout << " paragraph : " << index << std::endl;
+ std::cout << " index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+ std::cout << " expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+ return false;
+ }
+
+ if( run.characterRun.characterIndex != data.indices[index] )
+ {
+ std::cout << " Different index" << std::endl;
+ std::cout << " paragraph : " << index << std::endl;
+ std::cout << " index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+ std::cout << " expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+ return false;
+ }
+ if( run.characterRun.numberOfCharacters != data.numberOfParagraphCharacters[index] )
+ {
+ std::cout << " Different number of characters" << std::endl;
+ std::cout << " paragraph : " << index << std::endl;
+ std::cout << " index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+ std::cout << " expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * @brief Frees previously allocated bidirectional resources.
+ *
+ * @param[in] bidirectionalLineInfo Bidirectional info per line.
+ * @param[in] startIndex Index to the first line with bidirectional info to be freed.
+ * @param[in] endIndex Index to the last line with bidirectional info to be freed.
+ */
+void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
+ uint32_t startIndex,
+ uint32_t endIndex )
+{
+ // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+ for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + startIndex,
+ endIt = bidirectionalLineInfo.Begin() + endIndex;
+ it != endIt;
+ ++it )
+ {
+ BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+ free( bidiLineInfo.visualToLogicalMap );
+ }
+}
+
+bool ReorderLinesTest( const ReorderLinesData& data )
+{
+ // 1) Create the model.
+ LogicalModelPtr logicalModel = LogicalModel::New();
+ VisualModelPtr visualModel = VisualModel::New();
+ Size textArea(100.f, 300.f);
+ Size layoutSize;
+
+ // Create the model.
+ CreateTextModel( data.text,
+ textArea,
+ layoutSize,
+ logicalModel,
+ visualModel );
+
+ // 2) Clear the bidirectional line info data.
+ uint32_t startRemoveIndex = logicalModel->mBidirectionalLineInfo.Count();
+ uint32_t endRemoveIndex = startRemoveIndex;
+ ClearCharacterRuns( data.startIndex,
+ data.startIndex + data.numberOfCharacters - 1u,
+ logicalModel->mBidirectionalLineInfo,
+ startRemoveIndex,
+ endRemoveIndex );
+
+ // Index to the first index to be removed.
+
+ FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, startRemoveIndex, endRemoveIndex );
+ BidirectionalLineInfoRun* bidiLineBuffer = logicalModel->mBidirectionalLineInfo.Begin();
+ logicalModel->mBidirectionalLineInfo.Erase( bidiLineBuffer + startRemoveIndex,
+ bidiLineBuffer + endRemoveIndex );
+
+ // 3) Call the function ReorderLines()
+
+ ReorderLines( logicalModel->mBidirectionalParagraphInfo,
+ data.startIndex,
+ data.numberOfCharacters,
+ visualModel->mLines,
+ logicalModel->mBidirectionalLineInfo );
+
+ // 4) Compare the results.
+
+ if( data.numberOfLineInfo != logicalModel->mBidirectionalLineInfo.Count() )
+ {
+ // Different number of bidirectional lines.
+ std::cout << " different number of bidi lines : " << logicalModel->mBidirectionalLineInfo.Count() << ", expected : " << data.numberOfLineInfo << std::endl;
+ for( unsigned int index = 0u; index < logicalModel->mBidirectionalLineInfo.Count(); ++index )
+ {
+ const BidirectionalLineInfoRun& run = logicalModel->mBidirectionalLineInfo[index];
+ const BidiLineData& bidiLineData = data.bidiLineData[index];
+
+ std::cout << " bidi line : " << index << ", index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << std::endl;
+ std::cout << " expected index : " << bidiLineData.characterIndex << ", num chars : " << bidiLineData.numberOfCharacters << std::endl;
+ }
+ return false;
+ }
+
+ for( unsigned int index = 0u; index < data.numberOfLineInfo; ++index )
+ {
+ const BidirectionalLineInfoRun& run = logicalModel->mBidirectionalLineInfo[index];
+ const BidiLineData& bidiLineData = data.bidiLineData[index];
+
+ if( bidiLineData.characterIndex != run.characterRun.characterIndex )
+ {
+ std::cout << " bidi line : " << index << ", index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << std::endl;
+ std::cout << " expected index : " << bidiLineData.characterIndex << ", num chars : " << bidiLineData.numberOfCharacters << std::endl;
+ return false;
+ }
+ if( bidiLineData.numberOfCharacters != run.characterRun.numberOfCharacters )
+ {
+ std::cout << " bidi line : " << index << ", index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << std::endl;
+ std::cout << " expected index : " << bidiLineData.characterIndex << ", num chars : " << bidiLineData.numberOfCharacters << std::endl;
+ return false;
+ }
+
+ for( unsigned int i = 0u; i < run.characterRun.numberOfCharacters; ++i )
+ {
+ if( bidiLineData.visualToLogical[i] != run.visualToLogicalMap[i] )
+ {
+ std::cout << " v2l : ";
+ for( unsigned int i = 0u; i < run.characterRun.numberOfCharacters; ++i )
+ {
+ std::cout << run.visualToLogicalMap[i] << " ";
+ }
+ std::cout << std::endl;
+ std::cout << " expected v2l : ";
+ for( unsigned int i = 0u; i < run.characterRun.numberOfCharacters; ++i )
+ {
+ std::cout << bidiLineData.visualToLogical[i] << " ";
+ }
+ std::cout << std::endl;
+
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool GetMirroredTextTest( const GetMirroredTextData& data )
+{
+ // 1) Create the model.
+ LogicalModelPtr logicalModel = LogicalModel::New();
+ VisualModelPtr visualModel = VisualModel::New();
+ Size textArea(100.f, 60.f);
+ Size layoutSize;
+
+ // Create the model.
+ CreateTextModel( data.text,
+ textArea,
+ layoutSize,
+ logicalModel,
+ visualModel );
+
+ // 2) Call the GetMirroredText() function for the whole text
+ Vector<Character> mirroredText;
+ bool mirrored = false;
+ mirrored = GetMirroredText( logicalModel->mText,
+ logicalModel->mCharacterDirections,
+ logicalModel->mBidirectionalParagraphInfo,
+ 0u,
+ logicalModel->mText.Count(),
+ mirroredText );
+
+ // 3) Call the GetMirroredText() function for the given index + number of characters
+ mirrored = GetMirroredText( logicalModel->mText,
+ logicalModel->mCharacterDirections,
+ logicalModel->mBidirectionalParagraphInfo,
+ data.startIndex,
+ data.numberOfCharacters,
+ mirroredText );
+
+ // 4) Compare the results.
+
+ // Convert to utf8
+ std::string mirroredString;
+ Utf32ToUtf8( mirroredText.Begin(),
+ mirroredText.Count(),
+ mirroredString );
+
+ if( !mirrored && ( mirroredString != data.text ) )
+ {
+ std::cout << " No mirrored text and mirroredString != data.text." << std::endl;
+ std::cout << " mirrored string : [" << mirroredString << "]" << std::endl;
+ std::cout << " text : [" << data.text << "]" << std::endl;
+ return false;
+ }
+
+ if( mirrored && ( mirroredString == data.text ) )
+ {
+ std::cout << " Mirrored text and mirroredString == data.text." << std::endl;
+ std::cout << " mirrored string : [" << mirroredString << "]" << std::endl;
+ std::cout << " text : [" << data.text << "]" << std::endl;
+ return false;
+ }
+
+ if( mirrored && ( mirroredString != data.mirroredText ) )
+ {
+ std::cout << " Mirrored text and mirroredString != data.mirroredText." << std::endl;
+ std::cout << " mirrored string : [" << mirroredString << "]" << std::endl;
+ std::cout << " text : [" << data.mirroredText << "]" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
+{
+ // 1) Create the model.
+ LogicalModelPtr logicalModel = LogicalModel::New();
+ VisualModelPtr visualModel = VisualModel::New();
+ Size textArea(100.f, 60.f);
+ Size layoutSize;
+
+ // Create the model.
+ CreateTextModel( data.text,
+ textArea,
+ layoutSize,
+ logicalModel,
+ visualModel );
+
+ Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+
+ // 2) Clear the direction info data.
+ Vector<CharacterDirection>& directions = logicalModel->mCharacterDirections;
+
+ directions.Erase( directions.Begin() + data.startIndex,
+ directions.Begin() + data.startIndex + data.numberOfCharacters );
+
+ // 3) Call GetCharactersDirection() function.
+
+ GetCharactersDirection( bidirectionalInfo,
+ logicalModel->mText.Count(),
+ data.startIndex,
+ data.numberOfCharacters,
+ directions );
+
+ for( unsigned int index = 0u; index < logicalModel->mText.Count(); ++index )
+ {
+ if( data.directions[index] != directions[index] )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliSetBidirectionalInfo(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliSetBidirectionalInfo");
+
+ unsigned int indices01[] = {};
+ unsigned int numberOfCharacters01[] = {};
+ bool direction01[] = {};
+ unsigned int indices02[] = {};
+ unsigned int numberOfCharacters02[] = {};
+ bool direction02[] = {};
+ unsigned int indices03[] = { 17u, 48u };
+ unsigned int numberOfCharacters03[] = { 14u, 14u };
+ bool direction03[] = { true, true };
+ unsigned int indices04[] = { 17u, 31u, 79u };
+ unsigned int numberOfCharacters04[] = { 14u, 48u, 31u };
+ bool direction04[] = { true, false, true };
+ unsigned int indices05[] = { 17u, 41u, 117u };
+ unsigned int numberOfCharacters05[] = { 24u, 76u, 49u };
+ bool direction05[] = { true, false, true };
+ unsigned int indices06[] = { 17u, 48u };
+ unsigned int numberOfCharacters06[] = { 14u, 14u };
+ bool direction06[] = { true, true };
+ unsigned int indices07[] = { 17u, 31u, 79u };
+ unsigned int numberOfCharacters07[] = { 14u, 48u, 31u };
+ bool direction07[] = { true, false, true };
+ unsigned int indices08[] = { 17u, 41u, 117u };
+ unsigned int numberOfCharacters08[] = { 24u, 76u, 49u };
+ bool direction08[] = { true, false, true };
+
+ struct SetBidirectionalInfoData data[] =
+ {
+ {
+ "Zero characters",
+ "",
+ 0u,
+ 0u,
+ 0u,
+ indices01,
+ numberOfCharacters01,
+ direction01
+ },
+ {
+ "Some left to right paragraphs",
+ "Hello world\ndemo\n\n",
+ 0u,
+ 18u,
+ 0u,
+ indices02,
+ numberOfCharacters02,
+ direction02
+ },
+ {
+ "A mix of left to right and right to left paragraphs.",
+ "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
+ 0u,
+ 78u,
+ 2u,
+ indices03,
+ numberOfCharacters03,
+ direction03
+ },
+ {
+ "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
+ "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
+ 0u,
+ 126u,
+ 3u,
+ indices04,
+ numberOfCharacters04,
+ direction04
+ },
+ {
+ "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts.",
+ "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+ 0u,
+ 182u,
+ 3u,
+ indices05,
+ numberOfCharacters05,
+ direction05
+ },
+ {
+ "A mix of left to right and right to left paragraphs. Updates a left to right paragraph.",
+ "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
+ 31u,
+ 17u,
+ 2u,
+ indices06,
+ numberOfCharacters06,
+ direction06
+ },
+ {
+ "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
+ "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
+ 0u,
+ 126u,
+ 3u,
+ indices07,
+ numberOfCharacters07,
+ direction07
+ },
+ {
+ "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates initial paragraphs.",
+ "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+ 0u,
+ 41u,
+ 3u,
+ indices08,
+ numberOfCharacters08,
+ direction08
+ },
+ {
+ "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates mid paragraphs.",
+ "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+ 41u,
+ 76u,
+ 3u,
+ indices08,
+ numberOfCharacters08,
+ direction08
+ },
+ {
+ "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates from character 85",
+ "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+ 117u,
+ 65u,
+ 3u,
+ indices08,
+ numberOfCharacters08,
+ direction08
+ },
+ };
+ const unsigned int numberOfTests = 10u;
+
+ for( unsigned int index = 0u; index < numberOfTests; ++index )
+ {
+ if( !SetBidirectionalInfoTest( data[index] ) )
+ {
+ tet_result(TET_FAIL);
+ }
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
+
+int UtcDaliReorderLines(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliSetBidirectionalInfo");
+
+ unsigned int visualToLogical0301[] = { 0u, 1u, 2u, 3u, 4u, 5u, 9u, 8u, 7u, 6u, 10u };
+ unsigned int visualToLogical0302[] = { 3u, 2u, 1u, 0u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+ unsigned int visualToLogical0303[] = { 0u, 1u, 2u, 3u, 4u };
+ unsigned int visualToLogical0304[] = { 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0305[] = { 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0306[] = { 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0307[] = { 13u, 8u, 9u, 10u, 11u, 12u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0308[] = { 5u, 0u, 1u, 2u, 3u, 4u };
+ unsigned int visualToLogical0309[] = { 0u, 1u, 2u, 3u, 4u, 5u, 9u, 8u, 7u, 6u, 10u };
+ unsigned int visualToLogical0310[] = { 3u, 2u, 1u, 0u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+ unsigned int visualToLogical0311[] = { 0u, 1u, 2u, 3u, 4u };
+ unsigned int visualToLogical0312[] = { 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0313[] = { 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0314[] = { 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0315[] = { 13u, 8u, 9u, 10u, 11u, 12u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical0316[] = { 0u, 1u, 2u, 3u, 4u };
+
+ BidiLineData bidiLine01[] = {};
+ BidiLineData bidiLine02[] = {};
+ BidiLineData bidiLine03[] = {
+ {
+ 17u,
+ 11u,
+ visualToLogical0301
+ },
+ {
+ 28u,
+ 11u,
+ visualToLogical0302
+ },
+ {
+ 39u,
+ 5u,
+ visualToLogical0303
+ },
+ {
+ 44u,
+ 13u,
+ visualToLogical0304
+ },
+ {
+ 57u,
+ 11u,
+ visualToLogical0305
+ },
+ {
+ 68u,
+ 10u,
+ visualToLogical0306
+ },
+ {
+ 78u,
+ 14u,
+ visualToLogical0307
+ },
+ {
+ 92u,
+ 6u,
+ visualToLogical0308
+ },
+ {
+ 115u,
+ 11u,
+ visualToLogical0309
+ },
+ {
+ 126u,
+ 11u,
+ visualToLogical0310
+ },
+ {
+ 137u,
+ 5u,
+ visualToLogical0311
+ },
+ {
+ 142u,
+ 13u,
+ visualToLogical0312
+ },
+ {
+ 155u,
+ 11u,
+ visualToLogical0313
+ },
+ {
+ 166u,
+ 10u,
+ visualToLogical0314
+ },
+ {
+ 176u,
+ 14u,
+ visualToLogical0315
+ },
+ {
+ 190u,
+ 5u,
+ visualToLogical0316
+ },
+ };
+
+ struct ReorderLinesData data[] =
+ {
+ {
+ "Zero characters.",
+ "",
+ 0u,
+ 0u,
+ 0u,
+ bidiLine01
+ },
+ {
+ "Left to right text only.",
+ "Hello world demo\nhello world demo\nhello world demo.",
+ 0u,
+ 51u,
+ 0u,
+ bidiLine02
+ },
+ {
+ "Bidirectional paragraphs.",
+ "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+ 0u,
+ 195u,
+ 16u,
+ bidiLine03
+ },
+ {
+ "Bidirectional paragraphs. Update initial paragraphs.",
+ "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+ 0u,
+ 44u,
+ 16u,
+ bidiLine03
+ },
+ {
+ "Bidirectional paragraphs. Update middle paragraphs.",
+ "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+ 44u,
+ 54u,
+ 16u,
+ bidiLine03
+ },
+ {
+ "Bidirectional paragraphs. Update final paragraphs.",
+ "Hello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world\nHello world demo\nhello שלום עולם world demo\nשלום بالعالم עולם مرحبا שלום עולם بالعالم hello world",
+ 142u,
+ 53u,
+ 16u,
+ bidiLine03
+ },
+ };
+ const unsigned int numberOfTests = 6u;
+
+ for( unsigned int index = 0u; index < numberOfTests; ++index )
+ {
+ if( !ReorderLinesTest( data[index] ) )
+ {
+ tet_result(TET_FAIL);
+ }
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
+
+int UtcDaliGetMirroredText(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliGetMirroredText");
+
+ struct GetMirroredTextData data[] =
+ {
+ {
+ "Zero characters.",
+ "",
+ 0u,
+ 0u,
+ ""
+ },
+ {
+ "Left to right characters only.",
+ "Hello world\nhello world demo.",
+ 0u,
+ 29u,
+ "Hello world\nhello world demo."
+ },
+ {
+ "Right to left characters but with no characters to mirror.",
+ "שלום עולם\nمرحبا بالعالم",
+ 0u,
+ 23u,
+ "שלום עולם\nمرحبا بالعالم"
+ },
+ {
+ "Right to left characters with some characters to mirror.",
+ "שלום עולם\n(مرحبا بالعالم)",
+ 0u,
+ 25u,
+ "שלום עולם\n)مرحبا بالعالم("
+ },
+ {
+ "Right to left characters with some characters to mirror. Update last paragraph.",
+ "שלום עולם\n(مرحبا بالعالم)",
+ 10u,
+ 15u,
+ "שלום עולם\n)مرحبا بالعالم("
+ },
+ {
+ "Mix of bidirectional text. With more paragraphs.",
+ "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+ 0u,
+ 239u,
+ "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום )hello) world demo )עולם(\nשלום )مرحبا بالعالم עולם( )hello("
+ },
+ {
+ "Mix of bidirectional text. With more paragraphs. Update middle paragraphs.",
+ "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+ 29u,
+ 38u,
+ "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
+ },
+ {
+ "Mix of bidirectional text. With more paragraphs. Update middle paragraphs (2).",
+ "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+ 67u,
+ 100u,
+ "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
+ },
+ };
+ const unsigned int numberOfTests = 8u;
+
+ for( unsigned int index = 0u; index < numberOfTests; ++index )
+ {
+ if( !GetMirroredTextTest( data[index] ) )
+ {
+ tet_result(TET_FAIL);
+ }
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
+
+int UtcDaliGetCharactersDirection(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliGetCharactersDirection");
+
+ bool directions01[] = {};
+ bool directions02[] = {
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false };
+ bool directions03[] = {
+ true, true, true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true };
+ bool directions04[] = {
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, true, true, true, true, true, true,
+ true, true, true, false, true, true, true, true, true, true,
+ true, true, true, true, false, false, false, false, false, false,
+ false, false, false, false, false };
+ bool directions05[] = {
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, true, true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, true,
+ true, true, true, true, false, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, false,
+ false, false, false, false, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, false,
+ false, false, false, false, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, true, true, true,
+ true, true, false, false, false, false, false };
+
+ struct GetCharactersDirectionData data[] =
+ {
+ {
+ "Zero characters",
+ "",
+ 0u,
+ 0u,
+ directions01
+ },
+ {
+ "Left to right characters only",
+ "Hello world\nhello world demo",
+ 0u,
+ 28u,
+ directions02
+ },
+ {
+ "Right to left characters only",
+ "שלום עולם\nשלום עולם",
+ 0u,
+ 19u,
+ directions03
+ },
+ {
+ "Mix of bidirectional text",
+ "Hello world\nhello world שלום עולם\nשלום עולם hello world",
+ 0u,
+ 55u,
+ directions04
+ },
+ {
+ "Mix of bidirectional text. With more paragraphs.",
+ "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+ 0u,
+ 227u,
+ directions05
+ },
+ {
+ "Mix of bidirectional text. With more paragraphs. Update first paragraph.",
+ "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+ 0u,
+ 17u,
+ directions05
+ },
+ {
+ "Mix of bidirectional text. With more paragraphs. Update from character 29",
+ "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+ 29u,
+ 134u,
+ directions05
+ },
+ {
+ "Mix of bidirectional text. With more paragraphs. Update from character 163",
+ "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+ " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+ 163u,
+ 35u,
+ directions05
+ }
+ };
+ const unsigned int numberOfTests = 8u;
+
+ for( unsigned int index = 0u; index < numberOfTests; ++index )
+ {
+ if( !GetCharactersDirectionTest( data[index] ) )
+ {
+ tet_result(TET_FAIL);
+ }
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-model.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions.
+//
+// void SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
+// Length numberOfRuns,
+// CharacterIndex startIndex )
+
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct SetVisualToLogicalMapData
+{
+ std::string description; ///< Description of the test.
+ std::string text; ///< Input text.
+ unsigned int startIndex; ///< The start index from where the visual to logical conversion table is set.
+ unsigned int numberOfCharacters; ///< The number of characters to set.
+ Size textArea; ///< The size of the area where the text is laid-out.
+ unsigned int expectedNumberOfCharacters; ///< The expected number of characters.
+ unsigned int* visualToLogical; ///< The expected visual to logical conversion table.
+};
+
+bool SetVisualToLogicalMapTest( const SetVisualToLogicalMapData& data )
+{
+ std::cout << " testing : " << data.description << std::endl;
+ // Create the model.
+ LogicalModelPtr logicalModel = LogicalModel::New();
+ VisualModelPtr visualModel = VisualModel::New();
+ Size layoutSize;
+
+ // Create the model with the whole text.
+ CreateTextModel( data.text,
+ data.textArea,
+ layoutSize,
+ logicalModel,
+ visualModel );
+
+ // Get the visual to logical map.
+ Vector<CharacterIndex>& visualToLogicalMap = logicalModel->mVisualToLogicalMap;
+
+ // Compare the results.
+ if( data.expectedNumberOfCharacters != visualToLogicalMap.Count() )
+ {
+ std::cout << " differetn number of characters : " << visualToLogicalMap.Count() << ", expected : " << data.expectedNumberOfCharacters << std::endl;
+ return false;
+ }
+
+ for( unsigned int index = 0u; index < data.expectedNumberOfCharacters; ++index )
+ {
+ if( data.visualToLogical[index] != visualToLogicalMap[index] )
+ {
+ std::cout << " different visualToLogical table : " << std::endl;
+ for( unsigned int i = 0; i < data.expectedNumberOfCharacters; ++i )
+ {
+ std::cout << visualToLogicalMap[i] << " ";
+ }
+ std::cout << std::endl;
+ std::cout << " expected : " << std::endl;
+ for( unsigned int i = 0; i < data.expectedNumberOfCharacters; ++i )
+ {
+ std::cout << data.visualToLogical[i] << " ";
+ }
+ std::cout << std::endl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliSetVisualToLogicalMap(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliSetVisualToLogicalMap");
+
+ unsigned int* visualToLogical01 = NULL;
+ unsigned int* visualToLogical02 = NULL;
+ unsigned int visualToLogical03[] = { 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+ unsigned int visualToLogical04[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, };
+ unsigned int visualToLogical05[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 26u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u };
+ unsigned int visualToLogical06[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+ unsigned int visualToLogical07[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+ unsigned int visualToLogical08[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+ unsigned int visualToLogical09[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+
+ struct SetVisualToLogicalMapData data[] =
+ {
+ {
+ "Zero characters text",
+ "",
+ 0u,
+ 0u,
+ Size( 100.f, 300.f ),
+ 0u,
+ visualToLogical01
+ },
+ {
+ "Left to right text only",
+ "Hello world",
+ 0u,
+ 11u,
+ Size( 100.f, 300.f ),
+ 0u,
+ visualToLogical02
+ },
+ {
+ "Right to left text only",
+ "مرحبا بالعالم",
+ 0u,
+ 13u,
+ Size( 100.f, 300.f ),
+ 13u,
+ visualToLogical03
+ },
+ {
+ "Mix of left to right and right to left text.",
+ "Hello world, مرحبا بالعالم",
+ 0u,
+ 26u,
+ Size( 100.f, 300.f ),
+ 26u,
+ visualToLogical04
+ },
+ {
+ "Mix of left to right and right to left text.",
+ "Hello world, \nمرحبا بالعالم",
+ 0u,
+ 27u,
+ Size( 100.f, 300.f ),
+ 27u,
+ visualToLogical05
+ },
+ {
+ "Mix of left to right and right to left text.",
+ "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+ 0u,
+ 107u,
+ Size( 100.f, 300.f ),
+ 107u,
+ visualToLogical06
+ },
+ {
+ "Mix of left to right and right to left text. Updates from character index 5",
+ "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+ 5u,
+ 107u,
+ Size( 100.f, 300.f ),
+ 107u,
+ visualToLogical07
+ },
+ {
+ "Mix of left to right and right to left text. Updates from character index 39",
+ "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+ 39u,
+ 107u,
+ Size( 100.f, 300.f ),
+ 107u,
+ visualToLogical08
+ },
+ {
+ "Mix of left to right and right to left text. Updates from character index 70",
+ "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+ 70u,
+ 107u,
+ Size( 100.f, 300.f ),
+ 107u,
+ visualToLogical09
+ }
+ };
+ const unsigned int numberOfTests = 9u;
+
+ for( unsigned int index = 0u; index < numberOfTests; ++index )
+ {
+ if( !SetVisualToLogicalMapTest( data[index] ) )
+ {
+ tet_result(TET_FAIL);
+ }
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+#include "toolkit-text-model.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/metrics.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Frees previously allocated bidirectional resources.
+ *
+ * @param[in] bidirectionalLineInfo Bidirectional info per line.
+ * @param[in] index Index to the first line with bidirectional info to be freed.
+ */
+void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
+ uint32_t index )
+{
+ // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+ for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
+ endIt = bidirectionalLineInfo.End();
+ it != endIt;
+ ++it )
+ {
+ BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+ free( bidiLineInfo.visualToLogicalMap );
+ }
+}
+
+/**
+ * @brief Clear all the model data except for LogicalModel::mText.
+ *
+ * @param[in] characterIndex Clear data starting from the index.
+ */
+void ClearModelData( CharacterIndex characterIndex,
+ LogicalModelPtr logicalModel,
+ VisualModelPtr visualModel )
+{
+ // n.b. This does not Clear the mText from mLogicalModel
+
+ // Frees previously allocated resources.
+ FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
+
+ logicalModel->mScriptRuns.Clear();
+ logicalModel->mFontRuns.Clear();
+ logicalModel->mWordBreakInfo.Clear();
+ logicalModel->mBidirectionalParagraphInfo.Clear();
+ logicalModel->mCharacterDirections.Clear();
+ logicalModel->mBidirectionalLineInfo.Clear();
+ logicalModel->mLogicalToVisualMap.Clear();
+ logicalModel->mVisualToLogicalMap.Clear();
+ visualModel->mGlyphs.Clear();
+ visualModel->mGlyphsToCharacters.Clear();
+ visualModel->mCharactersToGlyph.Clear();
+ visualModel->mCharactersPerGlyph.Clear();
+ visualModel->mGlyphsPerCharacter.Clear();
+ visualModel->mGlyphPositions.Clear();
+ visualModel->mLines.Clear();
+ visualModel->mColorRuns.Clear();
+
+ visualModel->ClearCaches();
+}
+
+void CreateTextModel( const std::string& text,
+ const Size& textArea,
+ Size& layoutSize,
+ LogicalModelPtr logicalModel,
+ VisualModelPtr visualModel )
+{
+ // 1) Convert to utf32
+ Vector<Character>& utf32Characters = logicalModel->mText;
+ utf32Characters.Resize( text.size() );
+
+ const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( text.c_str() ),
+ text.size(),
+ &utf32Characters[0u] );
+ utf32Characters.Resize( numberOfCharacters );
+
+ // 2) Set the break and paragraph info.
+ Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
+ lineBreakInfo.Resize( numberOfCharacters );
+
+ SetLineBreakInfo( utf32Characters, lineBreakInfo );
+
+ if( 0u == numberOfCharacters )
+ {
+ // Nothing else to do if the number of characters is zero.
+ return;
+ }
+
+ // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
+ Vector<WordBreakInfo>& wordBreakInfo = logicalModel->mWordBreakInfo;
+ wordBreakInfo.Resize( numberOfCharacters );
+
+ SetWordBreakInfo( utf32Characters,
+ 0u,
+ numberOfCharacters,
+ wordBreakInfo );
+
+ // 3) Set the script info.
+ MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+ Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
+ multilanguageSupport.SetScripts( utf32Characters,
+ 0u,
+ numberOfCharacters,
+ scripts );
+
+ // 4) Set the font info
+ Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
+ Vector<FontRun>& validFonts = logicalModel->mFontRuns;
+
+ // The default font id.
+ FontDefaults fontDefaults;
+ fontDefaults.mFontDescription.family = "";
+ fontDefaults.familyDefined = true;
+ fontDefaults.mDefaultPointSize = 12.f;
+ fontDefaults.sizeDefined = true;
+
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.SetDpi( 96u, 96u );
+
+ const FontId defaultFontId = fontDefaults.GetFontId( fontClient );
+
+ // Validates the fonts. If there is a character with no assigned font it sets a default one.
+ // After this call, fonts are validated.
+ multilanguageSupport.ValidateFonts( utf32Characters,
+ scripts,
+ fontDescriptionRuns,
+ defaultFontId,
+ 0u,
+ numberOfCharacters,
+ validFonts );
+
+ // 5) Set the bidirectional info per paragraph.
+ Vector<Character> mirroredUtf32Characters;
+ bool textMirrored = false;
+
+ // Reserve some space for the vector of paragraph's bidirectional info.
+ Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+
+ // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+ SetBidirectionalInfo( utf32Characters,
+ scripts,
+ lineBreakInfo,
+ 0u,
+ numberOfCharacters,
+ bidirectionalInfo );
+
+ // 6) Set character directions.
+ Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
+ if( 0u != bidirectionalInfo.Count() )
+ {
+ // Only set the character directions if there is right to left characters.
+ GetCharactersDirection( bidirectionalInfo,
+ numberOfCharacters,
+ 0u,
+ numberOfCharacters,
+ characterDirections );
+
+
+ // This paragraph has right to left text. Some characters may need to be mirrored.
+ textMirrored = GetMirroredText( utf32Characters,
+ characterDirections,
+ bidirectionalInfo,
+ 0u,
+ numberOfCharacters,
+ mirroredUtf32Characters );
+ }
+ else
+ {
+ // There is no right to left characters. Clear the directions vector.
+ characterDirections.Clear();
+ }
+
+ // 7) Shape the text.
+
+ Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
+ Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
+ Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
+ Vector<GlyphIndex> newParagraphGlyphs;
+
+ const Length currentNumberOfGlyphs = glyphs.Count();
+ const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
+
+ ShapeText( textToShape,
+ lineBreakInfo,
+ scripts,
+ validFonts,
+ glyphs,
+ glyphsToCharactersMap,
+ charactersPerGlyph,
+ newParagraphGlyphs );
+
+ // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+ visualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
+ visualModel->CreateCharacterToGlyphTable( numberOfCharacters );
+
+ const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
+
+ // 8) Get the glyph metrics
+ MetricsPtr metrics = Metrics::New( fontClient );
+
+ const GlyphIndex glyphIndex = currentNumberOfGlyphs;
+
+ GlyphInfo* glyphsBuffer = glyphs.Begin() + glyphIndex;
+ metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
+
+ // Update the width and advance of all new paragraph characters.
+ for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
+ endIt = newParagraphGlyphs.End();
+ it != endIt;
+ ++it )
+ {
+ const GlyphIndex index = *it;
+ GlyphInfo& glyph = *( glyphsBuffer + ( index - glyphIndex ) );
+
+ glyph.xBearing = 0.f;
+ glyph.width = 0.f;
+ glyph.advance = 0.f;
+ }
+
+ // 9) Layout the text
+ LayoutEngine layoutEngine;
+ layoutEngine.SetMetrics( metrics );
+ layoutEngine.SetLayout( LayoutEngine::MULTI_LINE_BOX );
+
+ // Set the layout parameters.
+ const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+ LayoutParameters layoutParameters( textArea,
+ utf32Characters.Begin(),
+ lineBreakInfo.Begin(),
+ wordBreakInfo.Begin(),
+ ( 0u != characterDirections.Count() ) ? characterDirections.Begin() : NULL,
+ glyphs.Count(),
+ glyphs.Begin(),
+ glyphsToCharactersMap.Begin(),
+ charactersPerGlyph.Begin() );
+
+ // Get the character to glyph conversion table and set into the layout.
+ layoutParameters.charactersToGlyphsBuffer = charactersToGlyph.Begin();
+ // Get the glyphs per character table and set into the layout.
+ layoutParameters.glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
+
+ Vector<LineRun>& lines = visualModel->mLines;
+
+ Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
+ glyphPositions.Resize( numberOfGlyphs );
+
+ layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( logicalModel->mText.Count() - 1u ) ) );
+
+ layoutEngine.LayoutText( layoutParameters,
+ glyphPositions,
+ lines,
+ layoutSize );
+
+ // 10) Reorder the lines
+ if( 0u != bidirectionalInfo.Count() )
+ {
+ Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo;
+
+ // Get the lines
+ const Length numberOfLines = lines.Count();
+
+ // Reorder the lines.
+ bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
+ ReorderLines( bidirectionalInfo,
+ 0u,
+ numberOfCharacters,
+ lines,
+ bidirectionalLineInfo );
+
+ // Set the bidirectional info per line into the layout parameters.
+ layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
+ layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
+
+ // Set the bidirectional info into the model.
+ logicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
+ layoutParameters.numberOfBidirectionalInfoRuns,
+ 0u,
+ numberOfCharacters );
+
+ // Re-layout the text. Reorder those lines with right to left characters.
+ layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
+ glyphPositions );
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_TOOLKIT_TEXT_MODEL_H__
+#define __DALI_TOOLKIT_TEXT_MODEL_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
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/logical-model-impl.h>
+#include <dali-toolkit/internal/text/visual-model-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Creates and fills all the vectors of a text model: characters in utf32, segmentation info,
+ * scripts, fonts, bidi info, glyphs, conversion tables, etc.
+ *
+ * @param[in] text The given text.
+ * @param[in] textArea The area where to layout the text.
+ * @param[out] layoutSize The laid-out size.
+ * @param[out] Pointer to a logical text model instance.
+ * @param[out] Pointer to a visual text model instance.
+ */
+void CreateTextModel( const std::string& text,
+ const Size& textArea,
+ Size& layoutSize,
+ LogicalModelPtr logicalModel,
+ VisualModelPtr visualModel );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_MODEL_H__
void SetBidirectionalInfo( const Vector<Character>& text,
const Vector<ScriptRun>& scripts,
const Vector<LineBreakInfo>& lineBreakInfo,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
{
+ // Find where to insert the new paragraphs.
+ BidirectionalRunIndex bidiInfoIndex = 0u;
+ for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
+ endIt = bidirectionalInfo.End();
+ it != endIt;
+ ++it )
+ {
+ const BidirectionalParagraphInfoRun& run = *it;
+
+ if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+ {
+ // Found where to insert the bidi info.
+ break;
+ }
+ ++bidiInfoIndex;
+ }
+
// Traverse the script runs. If there is one with a right to left script, create the bidirectional info for the paragraph containing that script is needed.
// From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK.
// Index pointing the first character of the current paragraph.
- CharacterIndex paragraphCharacterIndex = 0u;
+ CharacterIndex paragraphCharacterIndex = startIndex;
// Pointer to the text buffer.
const Character* textBuffer = text.Begin();
// Pointer to the line break info buffer.
const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
- // The number of characters.
- const Length numberOfCharacters = text.Count();
-
// Handle to the bidirectional info module in text-abstraction.
TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+ const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
+ bool hasRightToLeftScript = false;
+
for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
endIt = scripts.End();
it != endIt;
++it )
{
const ScriptRun& scriptRun = *it;
- const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters;
+ const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters - 1u;
+
+ if( startIndex > lastScriptRunIndex )
+ {
+ // Skip the run as it has already been processed.
+ continue;
+ }
+
+ if( lastCharacter <= scriptRun.characterRun.characterIndex )
+ {
+ // Do not get bidirectional info beyond startIndex + numberOfCharacters.
+ break;
+ }
+
+ if( !hasRightToLeftScript && TextAbstraction::IsRightToLeftScript( scriptRun.script ) )
+ {
+ // The script is right to left.
+ hasRightToLeftScript = true;
+ }
- if( ( lastScriptRunIndex > paragraphCharacterIndex ) && // It isn't part of a previous paragraph.
- TextAbstraction::IsRightToLeftScript( scriptRun.script ) ) // The script is right to left.
+ if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + lastScriptRunIndex ) )
{
- // Find the paragraphs which contains this script run.
- // Consider:
- // 1) Different paragraphs may contain this script run.
- // ------||------------------- rtl sr ------------------------||-------------------
- // --||----- p -----||------------------ p -------------||-------- p ------||------
- //
- // 2) The paragraph which contains this script run may contain other right to left script runs.
- // -----||--- rtl sr ---||---- ltr sr ----||---------- rtl sr -----------||--------
- // -----||---------------------------------- p -----------------------------------|
-
- while( lastScriptRunIndex > paragraphCharacterIndex )
+ // A new paragraph has been found.
+
+ if( hasRightToLeftScript )
{
- // There is a paragraph which contains the current script.
-
- Length index = paragraphCharacterIndex;
- while( ( index < numberOfCharacters ) && ( paragraphCharacterIndex < lastScriptRunIndex ) )
- {
- if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) )
- {
- if( index >= scriptRun.characterRun.characterIndex )
- {
- // The Bidirectional run must have the same number of characters than the paragraph.
- BidirectionalParagraphInfoRun bidirectionalRun;
- bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
- bidirectionalRun.characterRun.numberOfCharacters = ( index - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
-
- // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
- bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
- bidirectionalRun.characterRun.numberOfCharacters );
-
- bidirectionalInfo.PushBack( bidirectionalRun );
- }
-
- // Update the character index of the next paragraph.
- paragraphCharacterIndex = index + 1u;
- }
- ++index;
- }
-
- // The last character is always a must-break, so there is no need to check if there is characters left.
+ // The Bidirectional run must have the same number of characters than the paragraph.
+ BidirectionalParagraphInfoRun bidirectionalRun;
+ bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
+ bidirectionalRun.characterRun.numberOfCharacters = ( lastScriptRunIndex - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
+
+ // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
+ bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
+ bidirectionalRun.characterRun.numberOfCharacters );
+
+ bidirectionalInfo.Insert( bidirectionalInfo.Begin() + bidiInfoIndex, bidirectionalRun );
+ ++bidiInfoIndex;
}
+
+ // Point to the next paragraph.
+ paragraphCharacterIndex = lastScriptRunIndex + 1u;
+
+ // Reset whether there is a right to left script.
+ hasRightToLeftScript = false;
}
}
+
+ // Update indices of the bidi runs.
+ for( Vector<BidirectionalParagraphInfoRun>::Iterator it = bidirectionalInfo.Begin() + bidiInfoIndex,
+ endIt = bidirectionalInfo.End();
+ it != endIt;
+ ++it )
+ {
+ BidirectionalParagraphInfoRun& run = *it;
+
+ run.characterRun.characterIndex += numberOfCharacters;
+ }
}
void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<LineRun>& lineRuns,
Vector<BidirectionalLineInfoRun>& lineInfoRuns )
{
+ // Find where to insert the new paragraphs.
+ BidirectionalLineRunIndex bidiLineInfoIndex = 0u;
+ for( Vector<BidirectionalLineInfoRun>::ConstIterator it = lineInfoRuns.Begin(),
+ endIt = lineInfoRuns.End();
+ it != endIt;
+ ++it )
+ {
+ const BidirectionalLineInfoRun& run = *it;
+
+ if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+ {
+ // Found where to insert the bidi line info.
+ break;
+ }
+ ++bidiLineInfoIndex;
+ }
+
// Handle to the bidirectional info module in text-abstraction.
TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+ const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
// Keep an index to the first line to be checked if it's contained inside the paragraph.
// Avoids check the lines from the beginning for each paragraph.
unsigned int lineIndex = 0u;
++it )
{
const BidirectionalParagraphInfoRun& paragraphInfo = *it;
+
+ if( paragraphInfo.characterRun.characterIndex < startIndex )
+ {
+ // Do not process, the paragraph has already been processed.
+ continue;
+ }
+
+ if( lastCharacter <= paragraphInfo.characterRun.characterIndex )
+ {
+ // Do not process paragraphs beyond startIndex + numberOfCharacters.
+ break;
+ }
+
const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( paragraphInfo.bidirectionalInfoIndex );
// Get the lines for this paragraph.
}
// Push the run into the vector.
- lineInfoRuns.PushBack( lineInfoRun );
+ lineInfoRuns.Insert( lineInfoRuns.Begin() + bidiLineInfoIndex, lineInfoRun );
+ ++bidiLineInfoIndex;
}
}
+
+ // Update indices of the bidi runs.
+ for( Vector<BidirectionalLineInfoRun>::Iterator it = lineInfoRuns.Begin() + bidiLineInfoIndex,
+ endIt = lineInfoRuns.End();
+ it != endIt;
+ ++it )
+ {
+ BidirectionalLineInfoRun& run = *it;
+
+ run.characterRun.characterIndex += numberOfCharacters;
+ }
}
bool GetMirroredText( const Vector<Character>& text,
const Vector<CharacterDirection>& directions,
const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<Character>& mirroredText )
{
bool hasTextMirrored = false;
Character* mirroredTextBuffer = mirroredText.Begin();
CharacterDirection* directionsBuffer = directions.Begin();
+ CharacterIndex index = startIndex;
+ const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
// Traverse the paragraphs and mirror the right to left ones.
for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
endIt = bidirectionalInfo.End();
{
const BidirectionalParagraphInfoRun& paragraph = *it;
+ if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
+ {
+ // Skip the paragraph as it has already been processed.
+ continue;
+ }
+
+ if( lastCharacter <= paragraph.characterRun.characterIndex )
+ {
+ // Do not get mirror characters beyond startIndex + numberOfCharacters.
+ break;
+ }
+
+ index += paragraph.characterRun.numberOfCharacters;
const bool tmpMirrored = bidirectionalSupport.GetMirroredText( mirroredTextBuffer + paragraph.characterRun.characterIndex,
directionsBuffer + paragraph.characterRun.characterIndex,
paragraph.characterRun.numberOfCharacters );
}
void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+ Length totalNumberOfCharacters,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<CharacterDirection>& directions )
{
// Handle to the bidirectional info module in text-abstraction.
TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
- CharacterIndex index = 0u;
- CharacterDirection* directionsBuffer = directions.Begin();
+ // Resize the vector.
+ directions.Resize( totalNumberOfCharacters );
+
+ // Whether the current buffer is being updated or is set from scratch.
+ const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+ CharacterDirection* directionsBuffer = NULL;
+ Vector<CharacterDirection> newDirections;
+
+ if( updateCurrentBuffer )
+ {
+ newDirections.Resize( numberOfCharacters );
+ directionsBuffer = newDirections.Begin();
+ }
+ else
+ {
+ directionsBuffer = directions.Begin();
+ }
+
+ const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+ CharacterIndex index = startIndex;
+
for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
endIt = bidirectionalInfo.End();
it != endIt;
{
const BidirectionalParagraphInfoRun& paragraph = *it;
- // Fills with left to right those paragraphs without right to left characters.
- memset( directionsBuffer + index, false, ( paragraph.characterRun.characterIndex - index ) * sizeof( bool ) );
- index += paragraph.characterRun.numberOfCharacters;
+ if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
+ {
+ // Skip the paragraph as it has already been processed.
+ continue;
+ }
+ if( lastCharacter <= paragraph.characterRun.characterIndex )
+ {
+ // Do not get the character directions beyond startIndex + numberOfCharacters.
+ break;
+ }
+
+ // Set the directions of any previous left to right characters.
+ const Length numberOfLeftToRightCharacters = paragraph.characterRun.characterIndex - index;
+ if( numberOfLeftToRightCharacters > 0u )
+ {
+ memset( directionsBuffer + index - startIndex, false, numberOfLeftToRightCharacters * sizeof( bool ) );
+ }
+
+ // Set the directions of the bidirectional text.
bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex,
- directionsBuffer + paragraph.characterRun.characterIndex,
+ directionsBuffer + paragraph.characterRun.characterIndex - startIndex,
paragraph.characterRun.numberOfCharacters );
+
+ // Update the index.
+ index += paragraph.characterRun.numberOfCharacters + numberOfLeftToRightCharacters;
}
// Fills with left to right those paragraphs without right to left characters.
- memset( directionsBuffer + index, false, ( directions.Count() - index ) * sizeof( bool ) );
+ memset( directionsBuffer + index - startIndex, false, ( lastCharacter - index ) * sizeof( bool ) );
+
+ // If the direction info is updated, it needs to be inserted in the model.
+ if( updateCurrentBuffer )
+ {
+ // Insert the directions in the given buffer.
+ directions.Insert( directions.Begin() + startIndex,
+ newDirections.Begin(),
+ newDirections.End() );
+ directions.Resize( totalNumberOfCharacters );
+ }
}
} // namespace Text
* @param[in] text Vector of UTF-32 characters.
* @param[in] scripts Vector containing the script runs for the whole text.
* @param[in] lineBreakInfo The line break info.
+ * @param[in] startIndex The character from where the bidirectional info is set.
+ * @param[in] numberOfCharacters The number of characters.
* @param[out] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
*/
void SetBidirectionalInfo( const Vector<Character>& text,
const Vector<ScriptRun>& scripts,
const Vector<LineBreakInfo>& lineBreakInfo,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo );
/**
* @pre The @p visualModel needs to have the laid-out lines info set.
*
* @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] startIndex The character from where the bidirectional info is set.
+ * @param[in] numberOfCharacters The number of characters.
* @param[in,out] lineRuns The line runs converted to characters.
* @param[out] lineInfoRuns line runs with the visual to logical conversion maps.
*/
void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<LineRun>& lineRuns,
Vector<BidirectionalLineInfoRun>& lineInfoRuns );
* @param[in] text The text.
* @param[in] directions Vector with the direction of each paragraph.
* @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] startIndex The character from where the text is mirrored.
+ * @param[in] numberOfCharacters The number of characters.
* @param[out] mirroredText The mirroredText.
*
* @return @e true if a character has been replaced.
bool GetMirroredText( const Vector<Character>& text,
const Vector<CharacterDirection>& directions,
const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<Character>& mirroredText );
/**
* @pre The @p logicalModel needs to have the bidirectional info indices for each paragraph set.
*
* @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] totalNumberOfCharacters The number of characters of the whole text.
+ * @param[in] startIndex The character from where the direction info is set.
+ * @param[in] numberOfCharacters The number of characters.
* @param[out] directions The direction, @e false is left to right and @e true is right to left, of each character of the paragraph.
*/
void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+ Length totalNumberOfCharacters,
+ CharacterIndex startIndex,
+ Length numberOfCharacters,
Vector<CharacterDirection>& directions );
} // namespace Text
}
void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
- Length numberOfRuns )
+ Length numberOfRuns,
+ CharacterIndex startIndex,
+ Length numberOfCharacters )
{
- if( 0u == numberOfRuns )
- {
- mVisualToLogicalMap.Clear();
- mLogicalToVisualMap.Clear();
- mVisualToLogicalCursorMap.Clear();
- }
- else
- {
- const Length numberOfCharacters = mText.Count();
- mVisualToLogicalMap.Resize( numberOfCharacters );
- mLogicalToVisualMap.Resize( numberOfCharacters );
+ mVisualToLogicalMap.Resize( numberOfCharacters );
+ mLogicalToVisualMap.Resize( numberOfCharacters );
- const Length numberOfCharactersPlus = numberOfCharacters + 1u;
- mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
+ const Length numberOfCharactersPlus = numberOfCharacters + 1u;
+ mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
- CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
- CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
+ CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
+ CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
- CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
+ CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
- CharacterIndex lastIndex = 0u;
- for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
- {
- const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
+ CharacterIndex lastIndex = startIndex;
+ for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
+ {
+ const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
- if( lastIndex < bidiLineInfo.characterRun.characterIndex )
- {
- // Fill with the identity.
- for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
- {
- *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
- }
- }
+ if( bidiLineInfo.characterRun.characterIndex + bidiLineInfo.characterRun.numberOfCharacters <= startIndex )
+ {
+ // Skip this paragraph. It has been already processed.
+ continue;
+ }
- // Fill the conversion table of the run.
- for( CharacterIndex index = 0u;
- index < bidiLineInfo.characterRun.numberOfCharacters;
- ++index, ++lastIndex )
+ if( lastIndex < bidiLineInfo.characterRun.characterIndex )
+ {
+ // Fill with the identity.
+ for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
{
- *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
+ *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
}
}
- // Complete with the identity if there are some left to right characters after the last right to left.
- for( ; lastIndex < numberOfCharacters; ++lastIndex )
+ // Fill the conversion table of the run.
+ for( CharacterIndex index = 0u;
+ index < bidiLineInfo.characterRun.numberOfCharacters;
+ ++index, ++lastIndex )
{
- *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
+ *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
}
+ }
- // Sets the logical to visual conversion map.
- for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
- {
- *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
- }
+ // 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;
+ }
+
+ // Sets the logical to visual conversion map.
+ for( CharacterIndex index = startIndex; index < numberOfCharacters; ++index )
+ {
+ *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
+ }
- // Sets the visual to logical conversion map for cursor positions.
+ // Sets the visual to logical conversion map for cursor positions.
- const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
- BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
- BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
+ const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
+ BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
+ BidirectionalParagraphInfoRun* bidirectionalParagraph = bidirectionalParagraphInfoBuffer;
- const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
+ const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
+
+ Length bidirectionalParagraphIndex = 0u;
+ bool isRightToLeftParagraph = false;
+ for( CharacterIndex index = startIndex; index < numberOfCharactersPlus; ++index )
+ {
+ if( bidirectionalParagraph &&
+ ( bidirectionalParagraph->characterRun.characterIndex == index ) )
+ {
+ isRightToLeftParagraph = *( modelCharacterDirections + index );
+ }
- Length bidirectionalParagraphIndex = 0u;
- bool isRightToLeftParagraph = false;
- for( CharacterIndex index = 0u; index < numberOfCharactersPlus; ++index )
+ if( 0u == index )
{
- if( bidirectionalParagraph &&
- ( bidirectionalParagraph->characterRun.characterIndex == index ) )
+ if( isRightToLeftParagraph )
{
- isRightToLeftParagraph = *( modelCharacterDirections + index );
+ *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
}
-
- if( 0u == index )
+ else // else logical position is zero.
{
- if( isRightToLeftParagraph )
- {
- *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
- }
- else // else logical position is zero.
- {
- *( modelVisualToLogicalCursorMap + index ) = 0u;
- }
+ *( modelVisualToLogicalCursorMap + index ) = 0u;
}
- else if( numberOfCharacters == index )
+ }
+ else if( numberOfCharacters == index )
+ {
+ if( isRightToLeftParagraph )
{
- if( isRightToLeftParagraph )
+ *( modelVisualToLogicalCursorMap + index ) = 0u;
+ }
+ else // else logical position is the number of characters.
+ {
+ *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
+ }
+ }
+ else
+ {
+ // Get the character indexed by index - 1 and index
+ // and calculate the logical position according the directions of
+ // both characters and the direction of the paragraph.
+
+ const CharacterIndex previousIndex = index - 1u;
+ const CharacterIndex logicalPosition0 = *( modelVisualToLogicalMapBuffer + previousIndex );
+ const CharacterIndex logicalPosition1 = *( modelVisualToLogicalMapBuffer + index );
+
+ const CharacterDirection direction0 = *( modelCharacterDirections + logicalPosition0 );
+ const CharacterDirection direction1 = *( modelCharacterDirections + logicalPosition1 );
+
+ if( direction0 == direction1 )
+ {
+ // Both glyphs have the same direction.
+ if( direction0 )
{
- *( modelVisualToLogicalCursorMap + index ) = 0u;
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
}
- else // else logical position is the number of characters.
+ else
{
- *( modelVisualToLogicalCursorMap + index ) = numberOfCharacters;
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
}
}
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( isRightToLeftParagraph )
{
- // Both glyphs have the same direction.
- if( direction0 )
+ if( direction1 )
{
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
}
else
{
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
}
}
else
{
- if( isRightToLeftParagraph )
+ if( direction0 )
{
- if( direction1 )
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition1 + 1u;
- }
- else
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition0;
- }
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
}
else
{
- if( direction0 )
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition1;
- }
- else
- {
- *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
- }
+ *( modelVisualToLogicalCursorMap + index ) = logicalPosition0 + 1u;
}
}
}
+ }
- if( bidirectionalParagraph &&
- ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
+ if( bidirectionalParagraph &&
+ ( bidirectionalParagraph->characterRun.characterIndex + bidirectionalParagraph->characterRun.numberOfCharacters == index ) )
+ {
+ isRightToLeftParagraph = false;
+ ++bidirectionalParagraphIndex;
+ if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
{
- isRightToLeftParagraph = false;
- ++bidirectionalParagraphIndex;
- if( bidirectionalParagraphIndex < numberOfBidirectionalParagraphs )
- {
- bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
- }
- else
- {
- bidirectionalParagraph = NULL;
- }
+ bidirectionalParagraph = bidirectionalParagraphInfoBuffer + bidirectionalParagraphIndex;
+ }
+ else
+ {
+ bidirectionalParagraph = NULL;
}
}
}
*
* @param[in] bidirectionalInfo Pointer to a buffer with all the bidirectional info runs.
* @param[in] numberOfRuns The number of bidirectional info runs.
+ * @param[in] startIndex Character index from where the conversion tables are set.
+ * @param[in] numberOfCharacters The number of characters.
*/
void SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
- Length numberOfRuns );
+ Length numberOfRuns,
+ CharacterIndex startIndex,
+ Length numberOfCharacters );
/**
* @brief Retrieves the logical character index for the given visual character index.
*/
CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const;
+ // Text style.
+
/**
* @brief Updates the text's style runs with the added or removed text.
*
SetBidirectionalInfo( utf32Characters,
scripts,
lineBreakInfo,
+ startIndex,
+ requestedNumberOfCharacters,
bidirectionalInfo );
if( 0u != bidirectionalInfo.Count() )
{
// Only set the character directions if there is right to left characters.
Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
- directions.Resize( numberOfCharacters );
-
GetCharactersDirection( bidirectionalInfo,
+ numberOfCharacters,
+ startIndex,
+ requestedNumberOfCharacters,
directions );
// This paragraph has right to left text. Some characters may need to be mirrored.
textMirrored = GetMirroredText( utf32Characters,
directions,
bidirectionalInfo,
+ startIndex,
+ requestedNumberOfCharacters,
mirroredUtf32Characters );
}
else
if( REORDER & operations )
{
Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
+ Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mLogicalModel->mBidirectionalLineInfo;
// Check first if there are paragraphs with bidirectional info.
if( 0u != bidirectionalInfo.Count() )
{
// Get the lines
const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
+ const CharacterIndex startIndex = 0u;
+ Length requestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
// Reorder the lines.
- Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
- lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
+ bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
ReorderLines( bidirectionalInfo,
+ startIndex,
+ requestedNumberOfCharacters,
lines,
- lineBidirectionalInfoRuns );
-
- // Set the bidirectional info into the model.
- const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
- mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
- numberOfBidirectionalInfoRuns );
+ bidirectionalLineInfo );
// Set the bidirectional info per line into the layout parameters.
- layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
- layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
+ layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
+ layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
+
+ // Set the bidirectional info into the model.
+ mImpl->mLogicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
+ layoutParameters.numberOfBidirectionalInfoRuns,
+ startIndex,
+ requestedNumberOfCharacters );
// Get the character to glyph conversion table and set into the layout.
layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
-
// Get the glyphs per character table and set into the layout.
layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
glyphPositions );
// Free the allocated memory used to store the conversion table in the bidirectional line info run.
- for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
- endIt = lineBidirectionalInfoRuns.End();
+ for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin(),
+ endIt = bidirectionalLineInfo.End();
it != endIt;
++it )
{
BidirectionalLineInfoRun& bidiLineInfo = *it;
free( bidiLineInfo.visualToLogicalMap );
+ bidiLineInfo.visualToLogicalMap = NULL;
}
+
+ bidirectionalLineInfo.Clear();
}
} // REORDER
typedef TextAbstraction::WordBreakInfo WordBreakInfo; ///< Word break info (break, no break). Possible values are: @e WORD_BREAK and @e WORD_NO_BREAK (in the TextAbstraction namespace).
typedef TextAbstraction::CharacterDirection CharacterDirection; ///< The character's direction: @e false is left to right, @e true is right to left.
-typedef uint32_t GlyphIndex; ///< An index into an array of glyphs.
-typedef uint32_t ScriptRunIndex; ///< An index into an array of script runs.
-typedef uint32_t FontRunIndex; ///< An index into an array of font runs.
-typedef uint32_t UnderlineRunIndex; ///< An index into an array of underline runs.
-typedef uint32_t BidirectionalRunIndex; ///< An index into an array of font runs.
-typedef uint32_t LineIndex; ///< An index into an array of lines.
+typedef uint32_t GlyphIndex; ///< An index into an array of glyphs.
+typedef uint32_t ScriptRunIndex; ///< An index into an array of script runs.
+typedef uint32_t FontRunIndex; ///< An index into an array of font runs.
+typedef uint32_t UnderlineRunIndex; ///< An index into an array of underline runs.
+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.
} // namespace Text