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 ReplaceBidirectionalInfo( LogicalModel& model,
166 CharacterIndex characterIndex,
167 Length numberOfCharactersToRemove,
168 Length numberOfCharactersToInsert )
172 void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
173 Vector<LineRun>& lineRuns,
174 Vector<BidirectionalLineInfoRun>& lineInfoRuns )
176 // Handle to the bidirectional info module in text-abstraction.
177 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
179 // Keep an index to the first line to be checked if it's contained inside the paragraph.
180 // Avoids check the lines from the beginning for each paragraph.
181 unsigned int lineIndex = 0u;
183 for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
184 endIt = bidirectionalInfo.End();
188 const BidirectionalParagraphInfoRun& paragraphInfo = *it;
189 const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( paragraphInfo.bidirectionalInfoIndex );
191 // Get the lines for this paragraph.
192 unsigned int firstLine = 0u;
193 unsigned int numberOfLines = 0u;
195 // Get an index to the first line and the number of lines of the current paragraph.
196 GetLines( paragraphInfo,
202 lineIndex = firstLine + numberOfLines;
204 // Traverse the lines and reorder them
205 for( Vector<LineRun>::Iterator lineIt = lineRuns.Begin() + firstLine,
206 endLineIt = lineRuns.Begin() + firstLine + numberOfLines;
210 LineRun& line = *lineIt;
212 // Sets the paragraph's direction.
213 line.direction = direction;
215 // Creates a bidirectional info for the line run.
216 BidirectionalLineInfoRun lineInfoRun;
217 lineInfoRun.characterRun.characterIndex = line.characterRun.characterIndex;
218 lineInfoRun.characterRun.numberOfCharacters = line.characterRun.numberOfCharacters;
219 lineInfoRun.direction = direction;
221 // Allocate space for the conversion maps.
222 // The memory is freed after the visual to logical to visual conversion tables are built in the logical model.
223 lineInfoRun.visualToLogicalMap = reinterpret_cast<CharacterIndex*>( malloc( line.characterRun.numberOfCharacters * sizeof( CharacterIndex ) ) );
225 // Reorders the line.
226 bidirectionalSupport.Reorder( paragraphInfo.bidirectionalInfoIndex,
227 line.characterRun.characterIndex - paragraphInfo.characterRun.characterIndex,
228 line.characterRun.numberOfCharacters,
229 lineInfoRun.visualToLogicalMap );
231 // Push the run into the vector.
232 lineInfoRuns.PushBack( lineInfoRun );
237 void ReorderLines( LogicalModel& logicalModel,
238 const VisualModel& visualModel,
239 CharacterIndex characterIndex,
240 Length numberOfCharactersToRemove,
241 Length numberOfCharactersToInsert )
245 bool GetMirroredText( const Vector<Character>& text,
246 Vector<Character>& mirroredText )
248 // Handle to the bidirectional info module in text-abstraction.
249 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
253 return bidirectionalSupport.GetMirroredText( mirroredText.Begin(),
254 mirroredText.Count() );
257 void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
258 Vector<CharacterDirection>& directions )
260 // Handle to the bidirectional info module in text-abstraction.
261 TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
263 CharacterIndex index = 0u;
264 CharacterDirection* directionsBuffer = directions.Begin();
265 for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
266 endIt = bidirectionalInfo.End();
270 const BidirectionalParagraphInfoRun& paragraph = *it;
272 // Fills with left to right those paragraphs without right to left characters.
273 memset( directionsBuffer + index, false, ( paragraph.characterRun.characterIndex - index ) * sizeof( bool ) );
274 index += paragraph.characterRun.numberOfCharacters;
276 bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex,
277 directionsBuffer + paragraph.characterRun.characterIndex,
278 paragraph.characterRun.numberOfCharacters );
281 // Fills with left to right those paragraphs without right to left characters.
282 memset( directionsBuffer + index, false, ( directions.Count() - index ) * sizeof( bool ) );
287 } // namespace Toolkit