2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/text/bidirectional-support.h>
23 #include <dali/devel-api/text-abstraction/bidirectional-support.h>
38 * @brief Get the lines of a paragraph.
40 * @param[in] paragraphInfo The paragraph.
41 * @param[in] lines The lines.
42 * @param[in] lineIndex Index pointing the first line to be checked.
43 * @param[out] firstLine Index to the first line of the paragraph.
44 * @param[out] numberOfLines The number of lines.
46 void GetLines( const BidirectionalParagraphInfoRun& paragraphInfo,
47 const Vector<LineRun>& lines,
48 unsigned int lineIndex,
49 unsigned int& firstLine,
50 unsigned int& numberOfLines )
52 firstLine = lineIndex;
55 const CharacterIndex lastCharacterIndex = paragraphInfo.characterRun.characterIndex + paragraphInfo.characterRun.numberOfCharacters;
56 bool firstLineFound = false;
58 for( Vector<LineRun>::ConstIterator it = lines.Begin() + lineIndex,
63 const LineRun& line = *it;
65 if( ( line.characterRun.characterIndex + line.characterRun.numberOfCharacters > paragraphInfo.characterRun.characterIndex ) &&
66 ( lastCharacterIndex > line.characterRun.characterIndex ) )
68 firstLineFound = true;
71 else if( lastCharacterIndex <= line.characterRun.characterIndex )
73 // nothing else to do.
86 void SetBidirectionalInfo( const Vector<Character>& text,
87 const Vector<ScriptRun>& scripts,
88 const Vector<LineBreakInfo>& lineBreakInfo,
89 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
91 // 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.
92 // From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK.
94 // Index pointing the first character of the current paragraph.
95 CharacterIndex paragraphCharacterIndex = 0u;
97 // Pointer to the text buffer.
98 const Character* textBuffer = text.Begin();
100 // Pointer to the line break info buffer.
101 const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
103 // The number of characters.
104 const Length numberOfCharacters = text.Count();
106 // Handle to the bidirectional info module in text-abstraction.
107 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
109 for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
110 endIt = scripts.End();
114 const ScriptRun& scriptRun = *it;
115 const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters;
117 if( TextAbstraction::IsRightToLeftScript( scriptRun.script ) && // The script is right to left.
118 ( lastScriptRunIndex > paragraphCharacterIndex ) ) // It isn't part of a previous paragraph.
120 // Find the paragraphs which contains this script run.
122 // 1) Different paragraphs may contain this script run.
123 // ------||------------------- rtl sr ------------------------||-------------------
124 // --||----- p -----||------------------ p -------------||-------- p ------||------
126 // 2) The paragraph which contains this script run may contain other right to left script runs.
127 // -----||--- rtl sr ---||---- ltr sr ----||---------- rtl sr -----------||--------
128 // -----||---------------------------------- p -----------------------------------|
130 while( lastScriptRunIndex > paragraphCharacterIndex )
132 // There is a paragraph which contains the current script.
134 Length index = paragraphCharacterIndex;
135 while( ( index < numberOfCharacters ) && ( paragraphCharacterIndex < lastScriptRunIndex ) )
137 if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) )
139 if( index >= scriptRun.characterRun.characterIndex )
141 // The Bidirectional run must have the same number of characters than the paragraph.
142 BidirectionalParagraphInfoRun bidirectionalRun;
143 bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
144 bidirectionalRun.characterRun.numberOfCharacters = ( index - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
146 // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
147 bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
148 bidirectionalRun.characterRun.numberOfCharacters );
150 bidirectionalInfo.PushBack( bidirectionalRun );
153 // Update the character index of the next paragraph.
154 paragraphCharacterIndex = index + 1u;
159 // The last character is always a must-break, so there is no need to check if there is characters left.
165 void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
166 Vector<LineRun>& lineRuns,
167 Vector<BidirectionalLineInfoRun>& lineInfoRuns )
169 // Handle to the bidirectional info module in text-abstraction.
170 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
172 // Keep an index to the first line to be checked if it's contained inside the paragraph.
173 // Avoids check the lines from the beginning for each paragraph.
174 unsigned int lineIndex = 0u;
176 for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
177 endIt = bidirectionalInfo.End();
181 const BidirectionalParagraphInfoRun& paragraphInfo = *it;
182 const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( paragraphInfo.bidirectionalInfoIndex );
184 // Get the lines for this paragraph.
185 unsigned int firstLine = 0u;
186 unsigned int numberOfLines = 0u;
188 // Get an index to the first line and the number of lines of the current paragraph.
189 GetLines( paragraphInfo,
195 lineIndex = firstLine + numberOfLines;
197 // Traverse the lines and reorder them
198 for( Vector<LineRun>::Iterator lineIt = lineRuns.Begin() + firstLine,
199 endLineIt = lineRuns.Begin() + firstLine + numberOfLines;
203 LineRun& line = *lineIt;
205 // Sets the paragraph's direction.
206 line.direction = direction;
208 // Creates a bidirectional info for the line run.
209 BidirectionalLineInfoRun lineInfoRun;
210 lineInfoRun.characterRun.characterIndex = line.characterRun.characterIndex;
211 lineInfoRun.characterRun.numberOfCharacters = line.characterRun.numberOfCharacters;
212 lineInfoRun.direction = direction;
214 // Allocate space for the conversion maps.
215 // The memory is freed after the visual to logical to visual conversion tables are built in the logical model.
216 lineInfoRun.visualToLogicalMap = reinterpret_cast<CharacterIndex*>( malloc( line.characterRun.numberOfCharacters * sizeof( CharacterIndex ) ) );
218 if( NULL != lineInfoRun.visualToLogicalMap )
220 // Reorders the line.
221 bidirectionalSupport.Reorder( paragraphInfo.bidirectionalInfoIndex,
222 line.characterRun.characterIndex - paragraphInfo.characterRun.characterIndex,
223 line.characterRun.numberOfCharacters,
224 lineInfoRun.visualToLogicalMap );
227 // Push the run into the vector.
228 lineInfoRuns.PushBack( lineInfoRun );
233 bool GetMirroredText( const Vector<Character>& text,
234 Vector<Character>& mirroredText )
236 // Handle to the bidirectional info module in text-abstraction.
237 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
241 return bidirectionalSupport.GetMirroredText( mirroredText.Begin(),
242 mirroredText.Count() );
245 void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
246 Vector<CharacterDirection>& directions )
248 // Handle to the bidirectional info module in text-abstraction.
249 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
251 CharacterIndex index = 0u;
252 CharacterDirection* directionsBuffer = directions.Begin();
253 for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
254 endIt = bidirectionalInfo.End();
258 const BidirectionalParagraphInfoRun& paragraph = *it;
260 // Fills with left to right those paragraphs without right to left characters.
261 memset( directionsBuffer + index, false, ( paragraph.characterRun.characterIndex - index ) * sizeof( bool ) );
262 index += paragraph.characterRun.numberOfCharacters;
264 bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex,
265 directionsBuffer + paragraph.characterRun.characterIndex,
266 paragraph.characterRun.numberOfCharacters );
269 // Fills with left to right those paragraphs without right to left characters.
270 memset( directionsBuffer + index, false, ( directions.Count() - index ) * sizeof( bool ) );
275 } // namespace Toolkit