2 * Copyright (c) 2022 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/bounded-paragraph-helper-functions.h>
22 #include <dali/devel-api/text-abstraction/script.h>
30 void MergeBoundedParagraphRunsWhenRemoveCharacters(const Vector<Character>& text,
31 const CharacterIndex& index,
32 const int& numberOfCharacters,
33 Vector<BoundedParagraphRun>& boundedParagraphRuns)
35 // This works on boundedParagraphRuns before applying on them the changes of the removed characters.
36 // Update to merge only when characters have been removed.
37 if(numberOfCharacters >= 0)
43 if(boundedParagraphRuns.Count() == 0u)
48 const Length numberOfRemovedCharacters = (Length)(-1 * numberOfCharacters);
49 const Length totalNumberOfCharacters = text.Count();
50 const CharacterIndex& firstIndexOfRemovedCharacters = index;
51 const CharacterIndex lastIndexOfRemovedCharacters = ((firstIndexOfRemovedCharacters + numberOfRemovedCharacters) > 0u) ? (firstIndexOfRemovedCharacters + numberOfRemovedCharacters - 1u) : firstIndexOfRemovedCharacters; // Note: Length is uint32. Extra validation to avoid a potential defects.
53 Length numberOfRuns = boundedParagraphRuns.Count();
54 Length firstRunIndexToUpdate = 0;
55 Length lastRunIndexToUpdate = 0;
56 bool noNeedToMerge = false;
58 // Find the first boundedParagraphRuns that is possible to be updated.
59 while(firstRunIndexToUpdate < numberOfRuns)
61 const CharacterIndex startCharIndex = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.characterIndex;
62 const CharacterIndex endCharIndex = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.GetEndCharacterIndex();
64 // In-case the paragraph separator of the plain text (before the current bounded paragraph) is removed.
65 // In-case the start index of the current bounded paragraph is between start and end indices of removed characters.
66 // In-case the end index of the current bounded paragraph is between start and end indices of removed characters.
67 if((startCharIndex == lastIndexOfRemovedCharacters + 1u) ||
68 ((firstIndexOfRemovedCharacters <= startCharIndex) && (startCharIndex <= lastIndexOfRemovedCharacters)) ||
69 ((firstIndexOfRemovedCharacters <= endCharIndex) && (endCharIndex <= lastIndexOfRemovedCharacters)))
73 else if(lastIndexOfRemovedCharacters + 1u < startCharIndex)
74 { // The whole removed characters are exist before the remaining bounded paragraphs.
78 firstRunIndexToUpdate++;
81 // There is no run was affected by the removed characters.
82 if(noNeedToMerge || (firstRunIndexToUpdate == numberOfRuns))
87 // Find the last boundedParagraphRuns that is possible to be updated.
88 lastRunIndexToUpdate = firstRunIndexToUpdate;
89 while(lastRunIndexToUpdate < numberOfRuns - 1u)
91 const CharacterIndex startCharIndex = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.characterIndex;
92 const CharacterIndex endCharIndex = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.GetEndCharacterIndex();
94 if((lastIndexOfRemovedCharacters < endCharIndex) ||
95 (lastIndexOfRemovedCharacters + 1u <= startCharIndex))
100 lastRunIndexToUpdate++;
103 // Remove all boundedParagraphRun between firstRunIndexToUpdate and lastRunIndexToUpdate
104 // At least one boundedParagraphRun between firstRunIndexToUpdate and lastRunIndexToUpdate
105 if(firstRunIndexToUpdate + 1u < lastRunIndexToUpdate)
107 Length runIndexToDelete = firstRunIndexToUpdate + 1u;
109 while(runIndexToDelete < lastRunIndexToUpdate)
111 Dali::Vector<BoundedParagraphRun>::Iterator paragraphToDelete = boundedParagraphRuns.Begin() + (runIndexToDelete);
112 boundedParagraphRuns.Remove(paragraphToDelete);
114 lastRunIndexToUpdate--;
119 CharacterIndex endCharIndexFirstRun = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.GetEndCharacterIndex();
121 if(firstRunIndexToUpdate == lastRunIndexToUpdate)
123 if(endCharIndexFirstRun < lastIndexOfRemovedCharacters)
125 boundedParagraphRuns[firstRunIndexToUpdate].characterRun.numberOfCharacters += (lastIndexOfRemovedCharacters - endCharIndexFirstRun);
130 CharacterIndex startCharIndexLastRun = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.characterIndex;
131 boundedParagraphRuns[firstRunIndexToUpdate].characterRun.numberOfCharacters += ((startCharIndexLastRun - endCharIndexFirstRun) > 0u) ? (startCharIndexLastRun - endCharIndexFirstRun - 1u) : 0u; // Note: Length is uint32. Extra validation to avoid a potential defects.
133 CharacterIndex endCharIndexLastRun = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.GetEndCharacterIndex();
135 if(endCharIndexLastRun < lastIndexOfRemovedCharacters)
137 boundedParagraphRuns[lastRunIndexToUpdate].characterRun.numberOfCharacters += (lastIndexOfRemovedCharacters - endCharIndexLastRun);
141 // Each endCharIndex for boundedParagraphRun is a paragraph separator.
142 // If not then keep adding characters until find paragraph separator.
143 Length runIndex = firstRunIndexToUpdate;
144 while(runIndex <= lastRunIndexToUpdate)
146 CharacterIndex endCharIndex = boundedParagraphRuns[runIndex].characterRun.GetEndCharacterIndex();
148 // The remaining text was not affected.
149 if(endCharIndex > lastIndexOfRemovedCharacters)
154 // Reference for numberOfCharacters in current run to update it
155 CharacterIndex& numberOfCharactersInRun = boundedParagraphRuns[runIndex].characterRun.numberOfCharacters;
157 // In-case arrived to the start of the next run and there is no paragraph separator.
158 // Merging the next run with the current run. Removing the next run.
159 if((runIndex + 1u < numberOfRuns) &&
160 (endCharIndex <= lastIndexOfRemovedCharacters) &&
161 ((lastIndexOfRemovedCharacters + 1u) < totalNumberOfCharacters) &&
162 (!TextAbstraction::IsNewParagraph(*(text.Begin() + lastIndexOfRemovedCharacters + 1u))))
164 numberOfCharactersInRun += boundedParagraphRuns[runIndex + 1u].characterRun.numberOfCharacters;
166 Dali::Vector<BoundedParagraphRun>::Iterator paragraphToDelete = boundedParagraphRuns.Begin() + (runIndex + 1u);
167 boundedParagraphRuns.Remove(paragraphToDelete);
170 lastRunIndexToUpdate--;
178 // Each startCharIndex-1u for boundedParagraphRun is a paragraph separator.
179 // If not then remove boundedParagraphRun.
180 if(numberOfRuns > 0u &&
181 firstIndexOfRemovedCharacters > 0u &&
182 boundedParagraphRuns[firstRunIndexToUpdate].characterRun.characterIndex > 0u)
184 const CharacterIndex startCharIndex = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.characterIndex;
186 if(firstIndexOfRemovedCharacters <= startCharIndex && startCharIndex <= lastIndexOfRemovedCharacters + 1u)
188 // Verify the paragraph separator before the first run to update
189 // In-case the paragraph separator is removed before the boundedParagraphRun.
190 // Remove the boundedParagraphRun.
191 if((!TextAbstraction::IsNewParagraph(*(text.Begin() + firstIndexOfRemovedCharacters - 1u))) &&
192 (!TextAbstraction::IsNewParagraph(*(text.Begin() + startCharIndex))))
194 Dali::Vector<BoundedParagraphRun>::Iterator paragraphToDelete = boundedParagraphRuns.Begin() + (firstRunIndexToUpdate);
195 boundedParagraphRuns.Remove(paragraphToDelete);
202 } // namespace Toolkit