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/controller/text-controller-impl-model-updater.h>
22 #include <dali/integration-api/debug.h>
25 #include <dali-toolkit/internal/text/bidirectional-support.h>
26 #include <dali-toolkit/internal/text/character-set-conversion.h>
27 #include <dali-toolkit/internal/text/color-segmentation.h>
28 #include <dali-toolkit/internal/text/hyphenator.h>
29 #include <dali-toolkit/internal/text/multi-language-support.h>
30 #include <dali-toolkit/internal/text/segmentation.h>
31 #include <dali-toolkit/internal/text/shaper.h>
32 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
34 namespace Dali::Toolkit::Text
38 #if defined(DEBUG_ENABLED)
39 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
42 // The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
43 // based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
44 constexpr float BRIGHTNESS_THRESHOLD = 0.179f;
45 constexpr float CONSTANT_R = 0.2126f;
46 constexpr float CONSTANT_G = 0.7152f;
47 constexpr float CONSTANT_B = 0.0722f;
48 constexpr Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
49 constexpr Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
50 constexpr Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
51 constexpr Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
52 constexpr Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
53 constexpr Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
54 constexpr Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
57 bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask operationsRequired)
59 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
61 // Calculate the operations to be done.
62 const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
64 if(Controller::NO_OPERATION == operations)
66 // Nothing to do if no operations are pending and required.
70 Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
71 Vector<Character> displayCharacters;
72 bool useHiddenText = false;
73 if(impl.mHiddenInput && impl.mEventData != nullptr)
75 if(impl.mEventData->mIsShowingPlaceholderText)
77 impl.mHiddenInput->InitPreviousTextCount();
81 impl.mHiddenInput->Substitute(srcCharacters, displayCharacters, impl.mEventData->mPrimaryCursorPosition);
86 Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
87 const Length numberOfCharacters = utf32Characters.Count();
89 // Index to the first character of the first paragraph to be updated.
90 CharacterIndex startIndex = 0u;
91 // Number of characters of the paragraphs to be removed.
92 Length paragraphCharacters = 0u;
94 impl.CalculateTextUpdateIndices(paragraphCharacters);
96 // Check whether the indices for updating the text is valid
97 if(numberOfCharacters > 0u &&
98 (impl.mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
99 impl.mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
101 std::string currentText;
102 Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
104 DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
105 DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
107 // Dump mTextUpdateInfo
108 DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
109 DALI_LOG_ERROR(" mTextUpdateInfo.mCharacterIndex = %u\n", impl.mTextUpdateInfo.mCharacterIndex);
110 DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToRemove);
111 DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToAdd);
112 DALI_LOG_ERROR(" mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mPreviousNumberOfCharacters);
113 DALI_LOG_ERROR(" mTextUpdateInfo.mParagraphCharacterIndex = %u\n", impl.mTextUpdateInfo.mParagraphCharacterIndex);
114 DALI_LOG_ERROR(" mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mRequestedNumberOfCharacters);
115 DALI_LOG_ERROR(" mTextUpdateInfo.mStartGlyphIndex = %u\n", impl.mTextUpdateInfo.mStartGlyphIndex);
116 DALI_LOG_ERROR(" mTextUpdateInfo.mStartLineIndex = %u\n", impl.mTextUpdateInfo.mStartLineIndex);
117 DALI_LOG_ERROR(" mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", impl.mTextUpdateInfo.mEstimatedNumberOfLines);
118 DALI_LOG_ERROR(" mTextUpdateInfo.mClearAll = %d\n", impl.mTextUpdateInfo.mClearAll);
119 DALI_LOG_ERROR(" mTextUpdateInfo.mFullRelayoutNeeded = %d\n", impl.mTextUpdateInfo.mFullRelayoutNeeded);
120 DALI_LOG_ERROR(" mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", impl.mTextUpdateInfo.mIsLastCharacterNewParagraph);
125 startIndex = impl.mTextUpdateInfo.mParagraphCharacterIndex;
127 if(impl.mTextUpdateInfo.mClearAll ||
128 (0u != paragraphCharacters))
130 impl.ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
133 impl.mTextUpdateInfo.mClearAll = false;
135 // Whether the model is updated.
136 bool updated = false;
138 Vector<LineBreakInfo>& lineBreakInfo = impl.mModel->mLogicalModel->mLineBreakInfo;
139 const Length requestedNumberOfCharacters = impl.mTextUpdateInfo.mRequestedNumberOfCharacters;
141 if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
143 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
144 // calculate the bidirectional info for each 'paragraph'.
145 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
146 // is not shaped together).
147 lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
149 SetLineBreakInfo(utf32Characters,
151 requestedNumberOfCharacters,
154 if(impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
155 impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
157 CharacterIndex end = startIndex + requestedNumberOfCharacters;
158 LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
160 for(CharacterIndex index = startIndex; index < end; index++)
162 CharacterIndex wordEnd = index;
163 while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
168 if((wordEnd + 1) == end) // add last char
173 Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
175 for(CharacterIndex i = 0; i < (wordEnd - index); i++)
179 *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
187 // Create the paragraph info.
188 impl.mModel->mLogicalModel->CreateParagraphInfo(startIndex,
189 requestedNumberOfCharacters);
193 const bool getScripts = Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations);
194 const bool validateFonts = Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations);
196 Vector<ScriptRun>& scripts = impl.mModel->mLogicalModel->mScriptRuns;
197 Vector<FontRun>& validFonts = impl.mModel->mLogicalModel->mFontRuns;
199 if(getScripts || validateFonts)
201 // Validates the fonts assigned by the application or assigns default ones.
202 // It makes sure all the characters are going to be rendered by the correct font.
203 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
207 // Retrieves the scripts used in the text.
208 multilanguageSupport.SetScripts(utf32Characters,
210 requestedNumberOfCharacters,
216 // Validate the fonts set through the mark-up string.
217 Vector<FontDescriptionRun>& fontDescriptionRuns = impl.mModel->mLogicalModel->mFontDescriptionRuns;
219 // Get the default font's description.
220 TextAbstraction::FontDescription defaultFontDescription;
221 TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * impl.GetFontSizeScale();
223 //Get the number of points per one unit of point-size
224 uint32_t numberOfPointsPerOneUnitOfPointSize = impl.mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
226 if(impl.IsShowingPlaceholderText() && impl.mEventData && (nullptr != impl.mEventData->mPlaceholderFont))
228 // If the placeholder font is set specifically, only placeholder font is changed.
229 defaultFontDescription = impl.mEventData->mPlaceholderFont->mFontDescription;
230 if(impl.mEventData->mPlaceholderFont->sizeDefined)
232 defaultPointSize = impl.mEventData->mPlaceholderFont->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
235 else if(nullptr != impl.mFontDefaults)
237 // Set the normal font and the placeholder font.
238 defaultFontDescription = impl.mFontDefaults->mFontDescription;
240 if(impl.mTextFitEnabled)
242 defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
246 defaultPointSize = impl.mFontDefaults->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
250 // Validates the fonts. If there is a character with no assigned font it sets a default one.
251 // After this call, fonts are validated.
252 multilanguageSupport.ValidateFonts(utf32Characters,
255 defaultFontDescription,
258 requestedNumberOfCharacters,
264 Vector<Character> mirroredUtf32Characters;
265 bool textMirrored = false;
266 const Length numberOfParagraphs = impl.mModel->mLogicalModel->mParagraphInfo.Count();
267 if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
269 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = impl.mModel->mLogicalModel->mBidirectionalParagraphInfo;
270 bidirectionalInfo.Reserve(numberOfParagraphs);
272 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
273 SetBidirectionalInfo(utf32Characters,
277 requestedNumberOfCharacters,
279 (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
280 impl.mLayoutDirection);
282 if(0u != bidirectionalInfo.Count())
284 // Only set the character directions if there is right to left characters.
285 Vector<CharacterDirection>& directions = impl.mModel->mLogicalModel->mCharacterDirections;
286 GetCharactersDirection(bidirectionalInfo,
289 requestedNumberOfCharacters,
292 // This paragraph has right to left text. Some characters may need to be mirrored.
293 // TODO: consider if the mirrored string can be stored as well.
295 textMirrored = GetMirroredText(utf32Characters,
299 requestedNumberOfCharacters,
300 mirroredUtf32Characters);
304 // There is no right to left characters. Clear the directions vector.
305 impl.mModel->mLogicalModel->mCharacterDirections.Clear();
310 Vector<GlyphInfo>& glyphs = impl.mModel->mVisualModel->mGlyphs;
311 Vector<CharacterIndex>& glyphsToCharactersMap = impl.mModel->mVisualModel->mGlyphsToCharacters;
312 Vector<Length>& charactersPerGlyph = impl.mModel->mVisualModel->mCharactersPerGlyph;
313 Vector<GlyphIndex> newParagraphGlyphs;
314 newParagraphGlyphs.Reserve(numberOfParagraphs);
316 const Length currentNumberOfGlyphs = glyphs.Count();
317 if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
319 const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
321 ShapeText(textToShape,
326 impl.mTextUpdateInfo.mStartGlyphIndex,
327 requestedNumberOfCharacters,
329 glyphsToCharactersMap,
333 // Create the 'number of glyphs' per character and the glyph to character conversion tables.
334 impl.mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
335 impl.mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
340 const Length numberOfGlyphs = static_cast<Length>(glyphs.Count()) - currentNumberOfGlyphs;
342 if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
344 GlyphInfo* glyphsBuffer = glyphs.Begin();
345 impl.mMetrics->GetGlyphMetrics(glyphsBuffer + impl.mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
347 // Update the width and advance of all new paragraph characters.
348 for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
350 const GlyphIndex index = *it;
351 GlyphInfo& glyph = *(glyphsBuffer + index);
353 glyph.xBearing = 0.f;
360 if((nullptr != impl.mEventData) &&
361 impl.mEventData->mPreEditFlag &&
362 (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
364 Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
365 impl.mEventData->mInputMethodContext.GetPreeditStyle(attrs);
366 Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
368 // Check the type of preedit and run it.
369 for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
371 Dali::InputMethodContext::PreeditAttributeData attrData = *it;
372 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
373 type = attrData.preeditType;
375 // Check the number of commit characters for the start position.
376 unsigned int numberOfCommit = impl.mEventData->mPrimaryCursorPosition - impl.mEventData->mPreEditLength;
377 Length numberOfIndices = attrData.endIndex - attrData.startIndex;
381 case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
383 // Add the underline for the pre-edit text.
384 UnderlinedGlyphRun underlineRun;
385 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
386 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
387 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
389 //Mark-up processor case
390 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
392 impl.CopyUnderlinedFromLogicalToVisualModels(false);
396 case Dali::InputMethodContext::PreeditStyle::REVERSE:
398 Vector4 textColor = impl.mModel->mVisualModel->GetTextColor();
399 ColorRun backgroundColorRun;
400 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
401 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
402 backgroundColorRun.color = textColor;
403 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
405 Vector4 backgroundColor = impl.mModel->mVisualModel->GetBackgroundColor();
406 if(backgroundColor.a == 0) // There is no text background color.
408 // Try use the control's background color.
409 if(nullptr != impl.mEditableControlInterface)
411 impl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
412 if(backgroundColor.a == 0) // There is no control background color.
414 // Determines black or white color according to text color.
415 // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
416 float L = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
417 backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
422 Vector<ColorRun> colorRuns;
423 colorRuns.Resize(1u);
424 ColorRun& colorRun = *(colorRuns.Begin());
425 colorRun.color = backgroundColor;
426 colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
427 colorRun.characterRun.numberOfCharacters = numberOfIndices;
428 impl.mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
430 //Mark-up processor case
431 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
433 impl.CopyUnderlinedFromLogicalToVisualModels(false);
437 case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
439 ColorRun backgroundColorRun;
440 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
441 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
442 backgroundColorRun.color = LIGHT_BLUE;
443 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
445 //Mark-up processor case
446 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
448 impl.CopyUnderlinedFromLogicalToVisualModels(false);
452 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
454 // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
455 ColorRun backgroundColorRun;
456 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
457 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
458 backgroundColorRun.color = BACKGROUND_SUB4;
459 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
461 UnderlinedGlyphRun underlineRun;
462 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
463 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
464 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
466 //Mark-up processor case
467 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
469 impl.CopyUnderlinedFromLogicalToVisualModels(false);
473 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
475 // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
476 ColorRun backgroundColorRun;
477 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
478 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
479 backgroundColorRun.color = BACKGROUND_SUB5;
480 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
482 UnderlinedGlyphRun underlineRun;
483 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
484 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
485 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
487 //Mark-up processor case
488 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
490 impl.CopyUnderlinedFromLogicalToVisualModels(false);
494 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
496 // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
497 ColorRun backgroundColorRun;
498 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
499 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
500 backgroundColorRun.color = BACKGROUND_SUB6;
501 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
503 UnderlinedGlyphRun underlineRun;
504 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
505 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
506 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
508 //Mark-up processor case
509 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
511 impl.CopyUnderlinedFromLogicalToVisualModels(false);
515 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
517 // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
518 ColorRun backgroundColorRun;
519 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
520 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
521 backgroundColorRun.color = BACKGROUND_SUB7;
522 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
524 UnderlinedGlyphRun underlineRun;
525 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
526 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
527 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
529 //Mark-up processor case
530 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
532 impl.CopyUnderlinedFromLogicalToVisualModels(false);
536 case Dali::InputMethodContext::PreeditStyle::NONE:
547 if(Controller::NO_OPERATION != (Controller::COLOR & operations))
549 // Set the color runs in glyphs.
550 SetColorSegmentationInfo(impl.mModel->mLogicalModel->mColorRuns,
551 impl.mModel->mVisualModel->mCharactersToGlyph,
552 impl.mModel->mVisualModel->mGlyphsPerCharacter,
554 impl.mTextUpdateInfo.mStartGlyphIndex,
555 requestedNumberOfCharacters,
556 impl.mModel->mVisualModel->mColors,
557 impl.mModel->mVisualModel->mColorIndices);
559 // Set the background color runs in glyphs.
560 SetColorSegmentationInfo(impl.mModel->mLogicalModel->mBackgroundColorRuns,
561 impl.mModel->mVisualModel->mCharactersToGlyph,
562 impl.mModel->mVisualModel->mGlyphsPerCharacter,
564 impl.mTextUpdateInfo.mStartGlyphIndex,
565 requestedNumberOfCharacters,
566 impl.mModel->mVisualModel->mBackgroundColors,
567 impl.mModel->mVisualModel->mBackgroundColorIndices);
572 if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
573 !((nullptr != impl.mEventData) &&
574 impl.mEventData->mPreEditFlag &&
575 (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count())))
577 //Mark-up processor case
578 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
580 impl.CopyUnderlinedFromLogicalToVisualModels(true);
581 impl.CopyStrikethroughFromLogicalToVisualModels();
582 impl.CopyCharacterSpacingFromLogicalToVisualModels();
588 // The estimated number of lines. Used to avoid reallocations when layouting.
589 impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
591 // Set the previous number of characters for the next time the text is updated.
592 impl.mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
597 } // namespace Dali::Toolkit::Text