Remove useless iteration when debug mode
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-run-container.h
1 #ifndef DALI_TOOLKIT_TEXT_RUN_CONTAINER_H
2 #define DALI_TOOLKIT_TEXT_RUN_CONTAINER_H
3
4 /*
5  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/text/character-run.h>
23
24 namespace Dali
25 {
26 namespace Toolkit
27 {
28 namespace Text
29 {
30 /**
31  * @brief Clears the runs starting from the given character index.
32  *
33  * @param[in] startIndex The starting character index used to remove runs.
34  * @param[in] endIndex The ending character index used to remove runs.
35  * @param[in,out] runs The text's runs.
36  * @param[out] startRemoveIndex The index to the first run to be removed.
37  * @param[out] endRemoveIndex The index to the last run to be removed.
38  */
39 template<typename T>
40 void ClearCharacterRuns(CharacterIndex startIndex,
41                         CharacterIndex endIndex,
42                         Vector<T>&     runs,
43                         uint32_t&      startRemoveIndex,
44                         uint32_t&      endRemoveIndex)
45 {
46   T* runsBuffer = runs.Begin();
47   T* run        = runsBuffer;
48
49   const Length length = runs.Count();
50   Length       index  = 0u;
51   for(index = 0u; index < length; ++index)
52   {
53     if((run->characterRun.characterIndex <= endIndex) &&
54        (startIndex < run->characterRun.characterIndex + run->characterRun.numberOfCharacters))
55     {
56       // Run found.
57
58       // Set the index to the first run to be removed.
59       startRemoveIndex = index;
60       break;
61     }
62
63     ++run;
64   }
65
66   run = (runsBuffer + startRemoveIndex);
67   for(index = startRemoveIndex; index < length; ++index)
68   {
69     if((run->characterRun.characterIndex > endIndex) ||
70        (startIndex >= run->characterRun.characterIndex + run->characterRun.numberOfCharacters))
71     {
72       // Run found. Nothing else to do.
73       break;
74     }
75     ++run;
76   }
77   endRemoveIndex = index;
78
79   // The number of characters to remove.
80   const Length numberOfCharactersRemoved = 1u + endIndex - startIndex;
81
82   // Update the character index of the next runs.
83   run = runsBuffer;
84   for(Length index = 0u; index < length; ++index)
85   {
86     if(run->characterRun.characterIndex > startIndex)
87     {
88       run->characterRun.characterIndex -= numberOfCharactersRemoved;
89     }
90
91     ++run;
92   }
93 }
94
95 /**
96  * @brief Clears the runs starting from the given character index.
97  *
98  * @param[in] startIndex The starting character index used to remove runs.
99  * @param[in] endIndex The ending character index used to remove runs.
100  * @param[in,out] runs The text's runs.
101  */
102 template<typename T>
103 void ClearCharacterRuns(CharacterIndex startIndex,
104                         CharacterIndex endIndex,
105                         Vector<T>&     runs)
106 {
107   uint32_t startRemoveIndex = runs.Count();
108   uint32_t endRemoveIndex   = startRemoveIndex;
109   ClearCharacterRuns(startIndex,
110                      endIndex,
111                      runs,
112                      startRemoveIndex,
113                      endRemoveIndex);
114
115   // Remove all remaining runs.
116   T* runBuffer = runs.Begin();
117   runs.Erase(runBuffer + startRemoveIndex, runBuffer + endRemoveIndex);
118 }
119
120 /**
121  * @brief Updates the number of characters and the character index of the text's style runs.
122  *
123  * If the @p numberOfCharacters is a negative value, it means the number of characters that are removed starting from the @p index.
124  *
125  * It deletes runs if all their characters are removed.
126  *
127  * @param[in] index Index to the first character updated.
128  * @param[in] numberOfCharacters The number of characters to be updated.
129  * @param[in] totalNumberOfCharacters Total number of characters of the text.
130  * @param[in,out] runs The text's style runs.
131  * @param[out] removedRuns The text's style removed runs.
132  */
133 template<typename T>
134 void UpdateCharacterRuns(CharacterIndex index,
135                          int            numberOfCharacters,
136                          Length         totalNumberOfCharacters,
137                          Vector<T>&     runs,
138                          Vector<T>&     removedRuns)
139 {
140   if(0 > numberOfCharacters)
141   {
142     // Remove characters.
143     const Length numberOfRemovedCharacters = -numberOfCharacters;
144
145     if((0u == index) && (numberOfRemovedCharacters == totalNumberOfCharacters))
146     {
147       // Set the removed runs.
148       removedRuns = runs;
149
150       // All characters are removed.
151       runs.Clear();
152
153       // Nothing else to do.
154       return;
155     }
156
157     const VectorBase::SizeType size = runs.Count();
158     // Temporary vector used to remove runs.
159     Vector<T> tempRuns;
160     // Reserve some space for the temporary vector.
161     tempRuns.Reserve(size);
162     removedRuns.Reserve(size);
163
164     // Whether any run has to be removed.
165     bool runsRemoved = false;
166
167     // Index to the last character added/removed.
168     const CharacterIndex lastIndex = index + numberOfRemovedCharacters - 1u;
169
170     // Update the style runs
171     for(typename Vector<T>::Iterator it    = runs.Begin(),
172                                      endIt = runs.End();
173         it != endIt;
174         ++it)
175     {
176       T& run = *it;
177
178       if(run.characterRun.numberOfCharacters == 0)
179         continue;
180
181       const CharacterIndex lastRunIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
182
183       if(lastRunIndex < index)
184       {
185         // The style run is not affected by the removed text.
186         tempRuns.PushBack(run);
187         continue;
188       }
189
190       if((index <= run.characterRun.characterIndex) &&
191          (lastIndex >= lastRunIndex))
192       {
193         // Add the removed run into the vector.
194         removedRuns.PushBack(run);
195
196         // All the characters are removed.
197         runsRemoved = true;
198       }
199       else
200       {
201         if(lastIndex < run.characterRun.characterIndex)
202         {
203           // Just move the character index.
204           run.characterRun.characterIndex -= numberOfRemovedCharacters;
205         }
206         else
207         {
208           if(run.characterRun.characterIndex < index)
209           {
210             // Remove characters starting from a character within the run.
211             run.characterRun.numberOfCharacters -= std::min(numberOfRemovedCharacters, 1u + lastRunIndex - index);
212           }
213           else
214           {
215             // Remove characters starting from a character located before the first index of the run.
216             run.characterRun.numberOfCharacters -= 1u + lastIndex - run.characterRun.characterIndex;
217             run.characterRun.characterIndex = index;
218           }
219         }
220
221         tempRuns.PushBack(run);
222       }
223     }
224
225     // Copy the temporary vector if there are runs removed.
226     if(runsRemoved)
227     {
228       runs = tempRuns;
229     }
230   }
231   else
232   {
233     // Add characters.
234
235     // Update the style runs
236     for(typename Vector<T>::Iterator it    = runs.Begin(),
237                                      endIt = runs.End();
238         it != endIt;
239         ++it)
240     {
241       T& run = *it;
242
243       if(run.characterRun.numberOfCharacters == 0)
244         continue;
245
246       // Update the number of characters of the style run.
247
248       if((0u == index) && (0u == run.characterRun.characterIndex))
249       {
250         run.characterRun.numberOfCharacters += numberOfCharacters;
251       }
252       else if(index <= run.characterRun.characterIndex)
253       {
254         run.characterRun.characterIndex += numberOfCharacters;
255       }
256       else if(index <= run.characterRun.characterIndex + run.characterRun.numberOfCharacters)
257       {
258         run.characterRun.numberOfCharacters += numberOfCharacters;
259       }
260     }
261   }
262 }
263
264 /**
265  * @brief Clears the runs starting from the given glyph index.
266  *
267  * @param[in] startIndex The starting glyph index used to remove runs.
268  * @param[in] endIndex The ending glyph index used to remove runs.
269  * @param[in,out] runs The text's runs.
270  * @param[out] startRemoveIndex The index to the first run to be removed.
271  * @param[out] endRemoveIndex The index to the last run to be removed.
272  */
273 template<typename T>
274 void ClearGlyphRuns(GlyphIndex startIndex,
275                     GlyphIndex endIndex,
276                     Vector<T>& runs,
277                     uint32_t&  startRemoveIndex,
278                     uint32_t&  endRemoveIndex)
279 {
280   T* runsBuffer = runs.Begin();
281   T* run        = runsBuffer;
282
283   const Length length = runs.Count();
284   Length       index  = 0u;
285   for(index = 0u; index < length; ++index)
286   {
287     if((run->glyphRun.glyphIndex <= endIndex) &&
288        (startIndex < run->glyphRun.glyphIndex + run->glyphRun.numberOfGlyphs))
289     {
290       // Run found.
291
292       // Set the index to the first run to be removed.
293       startRemoveIndex = index;
294       break;
295     }
296     ++run;
297   }
298
299   run = (runsBuffer + startRemoveIndex);
300   for(index = startRemoveIndex; index < length; ++index)
301   {
302     if((run->glyphRun.glyphIndex > endIndex) ||
303        (startIndex >= run->glyphRun.glyphIndex + run->glyphRun.numberOfGlyphs))
304     {
305       // Run found. Nothing else to do.
306       break;
307     }
308
309     ++run;
310   }
311   endRemoveIndex = index;
312
313   // The number of glyphs to remove.
314   const Length numberOfGlyphsRemoved = 1u + endIndex - startIndex;
315
316   // Update the glyph index of the next runs.
317   run = runsBuffer;
318   for(Length index = 0u; index < length; ++index)
319   {
320     if(run->glyphRun.glyphIndex > startIndex)
321     {
322       run->glyphRun.glyphIndex -= numberOfGlyphsRemoved;
323     }
324   }
325 }
326
327 /**
328  * @brief Clears the runs starting from the given glyph index.
329  *
330  * @param[in] startIndex The starting glyph index used to remove runs.
331  * @param[in] endIndex The ending glyph index used to remove runs.
332  * @param[in,out] runs The text's runs.
333  */
334 template<typename T>
335 void ClearGlyphRuns(GlyphIndex startIndex,
336                     GlyphIndex endIndex,
337                     Vector<T>& runs)
338 {
339   uint32_t startRemoveIndex = runs.Count();
340   uint32_t endRemoveIndex   = startRemoveIndex;
341   ClearGlyphRuns(startIndex,
342                  endIndex,
343                  runs,
344                  startRemoveIndex,
345                  endRemoveIndex);
346
347   // Remove all remaining runs.
348   T* runBuffer = runs.Begin();
349   runs.Erase(runBuffer + startRemoveIndex, runBuffer + endRemoveIndex);
350 }
351
352 } // namespace Text
353
354 } // namespace Toolkit
355
356 } // namespace Dali
357
358 #endif // DALI_TOOLKIT_TEXT_RUN_CONTAINER_H