2 * Copyright (c) 2021 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/logical-model-impl.h>
22 #include <dali-toolkit/internal/text/input-style.h>
23 #include <dali-toolkit/internal/text/text-run-container.h>
31 void FreeFontFamilyNames(Vector<FontDescriptionRun>& fontDescriptionRuns)
33 for(Vector<FontDescriptionRun>::Iterator it = fontDescriptionRuns.Begin(),
34 endIt = fontDescriptionRuns.End();
38 delete[](*it).familyName;
41 fontDescriptionRuns.Clear();
44 void FreeEmbeddedItems(Vector<EmbeddedItem>& embeddedItem)
46 for(Vector<EmbeddedItem>::Iterator it = embeddedItem.Begin(),
47 endIt = embeddedItem.End();
51 EmbeddedItem& item = *it;
58 LogicalModelPtr LogicalModel::New()
60 return LogicalModelPtr(new LogicalModel());
63 Script LogicalModel::GetScript(CharacterIndex characterIndex) const
65 // If this operation is too slow, consider a binary search.
67 const ScriptRun* const scriptRunBuffer = mScriptRuns.Begin();
68 for(Length index = 0u, length = mScriptRuns.Count(); index < length; ++index)
70 const ScriptRun* const scriptRun = scriptRunBuffer + index;
72 if((scriptRun->characterRun.characterIndex <= characterIndex) &&
73 (characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters))
75 return scriptRun->script;
79 return TextAbstraction::UNKNOWN;
82 CharacterDirection LogicalModel::GetCharacterDirection(CharacterIndex characterIndex) const
84 if(characterIndex >= mCharacterDirections.Count())
86 // The model has no right to left characters, so the vector of directions is void.
90 return *(mCharacterDirections.Begin() + characterIndex);
93 CharacterIndex LogicalModel::GetLogicalCursorIndex(CharacterIndex visualCursorIndex)
95 // The character's directions buffer.
96 const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
98 // The bidirectional line info.
99 const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
101 // Whether the paragraph starts with a right to left character.
102 const bool isRightToLeftParagraph = bidirectionalLineInfo->direction;
104 // The total number of characters of the line.
105 const Length lastCharacterIndex = bidirectionalLineInfo->characterRun.characterIndex + bidirectionalLineInfo->characterRun.numberOfCharacters;
107 CharacterIndex logicalCursorIndex = 0u;
109 if(bidirectionalLineInfo->characterRun.characterIndex == visualCursorIndex)
111 if(isRightToLeftParagraph)
113 logicalCursorIndex = lastCharacterIndex;
115 else // else logical position is the first of the line.
117 logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
120 else if(lastCharacterIndex == visualCursorIndex)
122 if(isRightToLeftParagraph)
124 logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
126 else // else logical position is the number of characters.
128 logicalCursorIndex = lastCharacterIndex;
133 // Get the character indexed by index - 1 and index
134 // and calculate the logical position according the directions of
135 // both characters and the direction of the paragraph.
137 const CharacterIndex previousVisualCursorIndex = visualCursorIndex - 1u;
138 const CharacterIndex previousLogicalCursorIndex = *(bidirectionalLineInfo->visualToLogicalMap + previousVisualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
139 const CharacterIndex currentLogicalCursorIndex = *(bidirectionalLineInfo->visualToLogicalMap + visualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
141 const CharacterDirection previousCharacterDirection = *(modelCharacterDirections + previousLogicalCursorIndex);
142 const CharacterDirection currentCharacterDirection = *(modelCharacterDirections + currentLogicalCursorIndex);
144 if(previousCharacterDirection == currentCharacterDirection)
146 // Both glyphs have the same direction.
147 if(previousCharacterDirection)
149 logicalCursorIndex = previousLogicalCursorIndex;
153 logicalCursorIndex = currentLogicalCursorIndex;
158 if(isRightToLeftParagraph)
160 if(currentCharacterDirection)
162 logicalCursorIndex = currentLogicalCursorIndex + 1u;
166 logicalCursorIndex = previousLogicalCursorIndex;
171 if(previousCharacterDirection)
173 logicalCursorIndex = currentLogicalCursorIndex;
177 logicalCursorIndex = previousLogicalCursorIndex + 1u;
183 return logicalCursorIndex;
186 CharacterIndex LogicalModel::GetLogicalCharacterIndex(CharacterIndex visualCharacterIndex)
188 // The bidirectional line info.
189 const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
191 return *(bidirectionalLineInfo->visualToLogicalMap + visualCharacterIndex - bidirectionalLineInfo->characterRun.characterIndex) + bidirectionalLineInfo->characterRun.characterIndex;
194 bool LogicalModel::FetchBidirectionalLineInfo(CharacterIndex characterIndex)
196 // The number of bidirectional lines.
197 const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count();
199 if(0u == numberOfBidirectionalLines)
201 // If there is no bidirectional info.
205 // Find the bidi line where the character is laid-out.
207 const BidirectionalLineInfoRun* const bidirectionalLineInfoBuffer = mBidirectionalLineInfo.Begin();
209 // Check first if the character is in the previously fetched line.
211 BidirectionalLineRunIndex bidiLineIndex = 0u;
212 CharacterIndex lastCharacterOfRightToLeftRun = 0u;
213 if(mBidirectionalLineIndex < numberOfBidirectionalLines)
215 const BidirectionalLineInfoRun& bidiLineRun = *(bidirectionalLineInfoBuffer + mBidirectionalLineIndex);
217 const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
218 if((bidiLineRun.characterRun.characterIndex <= characterIndex) &&
219 (characterIndex < lastCharacterOfRunPlusOne))
221 // The character is in the previously fetched bidi line.
226 // The character is not in the previously fetched line.
227 // Set the bidi line index from where to start the fetch.
229 if(characterIndex < bidiLineRun.characterRun.characterIndex)
231 // Start the fetch from the beginning.
236 // Start the fetch from the next line.
237 bidiLineIndex = mBidirectionalLineIndex + 1u;
238 lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
243 // The character has not been found in the previously fetched bidi line.
244 for(Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLineInfoBuffer + bidiLineIndex,
245 endIt = mBidirectionalLineInfo.End();
247 ++it, ++bidiLineIndex)
249 const BidirectionalLineInfoRun& bidiLineRun = *it;
251 if((lastCharacterOfRightToLeftRun < characterIndex) &&
252 (characterIndex < bidiLineRun.characterRun.characterIndex))
254 // The character is not inside a bidi line.
258 const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
259 lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
260 if((bidiLineRun.characterRun.characterIndex <= characterIndex) &&
261 (characterIndex < lastCharacterOfRunPlusOne))
263 // Bidi line found. Fetch the line.
264 mBidirectionalLineIndex = bidiLineIndex;
272 BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const
274 return mBidirectionalLineIndex;
277 void LogicalModel::UpdateTextStyleRuns(CharacterIndex index, int numberOfCharacters)
279 const Length totalNumberOfCharacters = mText.Count();
281 // Process the color runs.
282 Vector<ColorRun> removedColorRuns;
283 UpdateCharacterRuns<ColorRun>(index,
285 totalNumberOfCharacters,
289 // Process the background color runs.
290 Vector<ColorRun> removedBackgroundColorRuns;
291 UpdateCharacterRuns<ColorRun>(index,
293 totalNumberOfCharacters,
294 mBackgroundColorRuns,
295 removedBackgroundColorRuns);
297 // Process the font description runs.
298 Vector<FontDescriptionRun> removedFontDescriptionRuns;
299 UpdateCharacterRuns<FontDescriptionRun>(index,
301 totalNumberOfCharacters,
302 mFontDescriptionRuns,
303 removedFontDescriptionRuns);
305 // Free memory allocated for the font family name.
306 FreeFontFamilyNames(removedFontDescriptionRuns);
309 void LogicalModel::RetrieveStyle(CharacterIndex index, InputStyle& style)
311 unsigned int runIndex = 0u;
313 // Set the text color.
314 bool colorOverriden = false;
315 unsigned int colorIndex = 0u;
316 const ColorRun* const colorRunsBuffer = mColorRuns.Begin();
317 for(Vector<ColorRun>::ConstIterator it = colorRunsBuffer,
318 endIt = mColorRuns.End();
322 const ColorRun& colorRun = *it;
324 if((colorRun.characterRun.characterIndex <= index) &&
325 (index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters))
327 colorIndex = runIndex;
328 colorOverriden = true;
332 // Set the text's color if it's overriden.
335 style.textColor = (*(colorRunsBuffer + colorIndex)).color;
336 style.isDefaultColor = false;
339 // Reset the run index.
342 // Set the font's parameters.
343 bool nameOverriden = false;
344 bool weightOverriden = false;
345 bool widthOverriden = false;
346 bool slantOverriden = false;
347 bool sizeOverriden = false;
348 unsigned int nameIndex = 0u;
349 unsigned int weightIndex = 0u;
350 unsigned int widthIndex = 0u;
351 unsigned int slantIndex = 0u;
352 unsigned int sizeIndex = 0u;
353 const FontDescriptionRun* const fontDescriptionRunsBuffer = mFontDescriptionRuns.Begin();
354 for(Vector<FontDescriptionRun>::ConstIterator it = fontDescriptionRunsBuffer,
355 endIt = mFontDescriptionRuns.End();
359 const FontDescriptionRun& fontDescriptionRun = *it;
361 if((fontDescriptionRun.characterRun.characterIndex <= index) &&
362 (index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters))
364 if(fontDescriptionRun.familyDefined)
366 nameIndex = runIndex;
367 nameOverriden = true;
370 if(fontDescriptionRun.weightDefined)
372 weightIndex = runIndex;
373 weightOverriden = true;
376 if(fontDescriptionRun.widthDefined)
378 widthIndex = runIndex;
379 widthOverriden = true;
382 if(fontDescriptionRun.slantDefined)
384 slantIndex = runIndex;
385 slantOverriden = true;
388 if(fontDescriptionRun.sizeDefined)
390 sizeIndex = runIndex;
391 sizeOverriden = true;
396 // Set the font's family name if it's overriden.
399 const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + nameIndex);
401 style.familyName = std::string(fontDescriptionRun.familyName, fontDescriptionRun.familyLength);
402 style.isFamilyDefined = true;
405 // Set the font's weight if it's overriden.
408 const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + weightIndex);
410 style.weight = fontDescriptionRun.weight;
411 style.isWeightDefined = true;
414 // Set the font's width if it's overriden.
417 const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + widthIndex);
419 style.width = fontDescriptionRun.width;
420 style.isWidthDefined = true;
423 // Set the font's slant if it's overriden.
426 const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + slantIndex);
428 style.slant = fontDescriptionRun.slant;
429 style.isSlantDefined = true;
432 // Set the font's size if it's overriden.
435 const FontDescriptionRun& fontDescriptionRun = *(fontDescriptionRunsBuffer + sizeIndex);
437 style.size = static_cast<float>(fontDescriptionRun.size) / 64.f;
438 style.isSizeDefined = true;
442 void LogicalModel::ClearFontDescriptionRuns()
444 FreeFontFamilyNames(mFontDescriptionRuns);
447 void LogicalModel::CreateParagraphInfo(CharacterIndex startIndex,
448 Length numberOfCharacters)
450 const Length totalNumberOfCharacters = mLineBreakInfo.Count();
452 // Count the number of LINE_MUST_BREAK to reserve some space for the vector of paragraph's info.
453 Vector<CharacterIndex> paragraphs;
454 paragraphs.Reserve(numberOfCharacters);
455 const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = mLineBreakInfo.Begin();
456 const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
457 for(Length index = startIndex; index < lastCharacterIndexPlusOne; ++index)
459 if(TextAbstraction::LINE_MUST_BREAK == *(lineBreakInfoBuffer + index))
461 paragraphs.PushBack(index);
465 // Whether the current paragraphs are updated or set from scratch.
466 const bool updateCurrentParagraphs = numberOfCharacters < totalNumberOfCharacters;
468 // Reserve space for current paragraphs plus new ones.
469 const Length numberOfNewParagraphs = paragraphs.Count();
470 const Length totalNumberOfParagraphs = mParagraphInfo.Count() + numberOfNewParagraphs;
471 mParagraphInfo.Resize(totalNumberOfParagraphs);
473 ParagraphRun* paragraphInfoBuffer = NULL;
474 Vector<ParagraphRun> newParagraphs;
476 if(updateCurrentParagraphs)
478 newParagraphs.Resize(numberOfNewParagraphs);
479 paragraphInfoBuffer = newParagraphs.Begin();
483 paragraphInfoBuffer = mParagraphInfo.Begin();
486 // Find where to insert the new paragraphs.
487 ParagraphRunIndex paragraphIndex = 0u;
488 CharacterIndex firstIndex = startIndex;
490 if(updateCurrentParagraphs)
492 for(Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
493 endIt = mParagraphInfo.Begin() + totalNumberOfParagraphs - numberOfNewParagraphs;
497 const ParagraphRun& paragraph(*it);
499 if(startIndex < paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters)
501 firstIndex = paragraph.characterRun.characterIndex;
509 // Create the paragraph info.
510 ParagraphRunIndex newParagraphIndex = 0u;
511 for(Vector<CharacterIndex>::ConstIterator it = paragraphs.Begin(),
512 endIt = paragraphs.End();
514 ++it, ++newParagraphIndex)
516 const CharacterIndex index = *it;
518 ParagraphRun& paragraph = *(paragraphInfoBuffer + newParagraphIndex);
519 paragraph.characterRun.characterIndex = firstIndex;
520 paragraph.characterRun.numberOfCharacters = 1u + index - firstIndex;
522 firstIndex += paragraph.characterRun.numberOfCharacters;
525 // Insert the new paragraphs.
526 if(updateCurrentParagraphs)
528 mParagraphInfo.Insert(mParagraphInfo.Begin() + paragraphIndex,
529 newParagraphs.Begin(),
530 newParagraphs.End());
532 mParagraphInfo.Resize(totalNumberOfParagraphs);
534 // Update the next paragraph indices.
535 for(Vector<ParagraphRun>::Iterator it = mParagraphInfo.Begin() + paragraphIndex + newParagraphs.Count(),
536 endIt = mParagraphInfo.End();
540 ParagraphRun& paragraph(*it);
542 paragraph.characterRun.characterIndex += numberOfCharacters;
547 void LogicalModel::FindParagraphs(CharacterIndex index,
548 Length numberOfCharacters,
549 Vector<ParagraphRunIndex>& paragraphs)
551 // Reserve som space for the paragraph indices.
552 paragraphs.Reserve(mParagraphInfo.Count());
554 // Traverse the paragraphs to find which ones contain the given characters.
555 ParagraphRunIndex paragraphIndex = 0u;
556 for(Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
557 endIt = mParagraphInfo.End();
559 ++it, ++paragraphIndex)
561 const ParagraphRun& paragraph(*it);
563 if((paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters > index) &&
564 (paragraph.characterRun.characterIndex < index + numberOfCharacters))
566 paragraphs.PushBack(paragraphIndex);
571 void LogicalModel::ClearEmbeddedImages()
573 FreeEmbeddedItems(mEmbeddedItems);
576 LogicalModel::~LogicalModel()
578 ClearFontDescriptionRuns();
579 ClearEmbeddedImages();
582 LogicalModel::LogicalModel()
583 : mBidirectionalLineIndex(0u)
589 } // namespace Toolkit