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>
23 #include <dali/integration-api/trace.h>
24 #include <dali/public-api/math/math-utils.h>
27 #include <dali-toolkit/internal/text/bidirectional-support.h>
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/color-segmentation.h>
30 #include <dali-toolkit/internal/text/hyphenator.h>
31 #include <dali-toolkit/internal/text/multi-language-support.h>
32 #include <dali-toolkit/internal/text/segmentation.h>
33 #include <dali-toolkit/internal/text/shaper.h>
34 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
36 namespace Dali::Toolkit::Text
40 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
44 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
46 // The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
47 // based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
48 constexpr float BRIGHTNESS_THRESHOLD = 0.179f;
49 constexpr float CONSTANT_R = 0.2126f;
50 constexpr float CONSTANT_G = 0.7152f;
51 constexpr float CONSTANT_B = 0.0722f;
52 constexpr Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
53 constexpr Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
54 constexpr Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
55 constexpr Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
56 constexpr Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
57 constexpr Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
58 constexpr Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
61 bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask operationsRequired)
63 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
65 // Calculate the operations to be done.
66 const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
68 if(Controller::NO_OPERATION == operations)
70 // Nothing to do if no operations are pending and required.
73 DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_MODEL_UPDATE");
75 Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
76 Vector<Character> displayCharacters;
77 bool useHiddenText = false;
78 if(impl.mHiddenInput && impl.mEventData != nullptr)
80 if(impl.mEventData->mIsShowingPlaceholderText)
82 impl.mHiddenInput->InitPreviousTextCount();
86 impl.mHiddenInput->Substitute(srcCharacters, displayCharacters, impl.mEventData->mPrimaryCursorPosition);
91 Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
92 const Length numberOfCharacters = utf32Characters.Count();
94 // Index to the first character of the first paragraph to be updated.
95 CharacterIndex startIndex = 0u;
96 // Number of characters of the paragraphs to be removed.
97 Length paragraphCharacters = 0u;
99 impl.CalculateTextUpdateIndices(paragraphCharacters);
101 // Check whether the indices for updating the text is valid
102 if(impl.mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
103 impl.mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters)
105 if(numberOfCharacters == 0u)
107 impl.mTextUpdateInfo.Clear();
108 impl.mTextUpdateInfo.mClearAll = true;
110 else // numberOfCharacters > 0u
112 std::string currentText;
113 Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
115 DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
116 DALI_LOG_ERROR("Number of characters: %d, current text is: %s paragraphCharacters: %d\n", numberOfCharacters, currentText.c_str(), paragraphCharacters);
118 // Dump mTextUpdateInfo
119 DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
120 DALI_LOG_ERROR(" mTextUpdateInfo.mCharacterIndex = %u\n", impl.mTextUpdateInfo.mCharacterIndex);
121 DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToRemove);
122 DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToAdd);
123 DALI_LOG_ERROR(" mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mPreviousNumberOfCharacters);
124 DALI_LOG_ERROR(" mTextUpdateInfo.mParagraphCharacterIndex = %u\n", impl.mTextUpdateInfo.mParagraphCharacterIndex);
125 DALI_LOG_ERROR(" mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mRequestedNumberOfCharacters);
126 DALI_LOG_ERROR(" mTextUpdateInfo.mStartGlyphIndex = %u\n", impl.mTextUpdateInfo.mStartGlyphIndex);
127 DALI_LOG_ERROR(" mTextUpdateInfo.mStartLineIndex = %u\n", impl.mTextUpdateInfo.mStartLineIndex);
128 DALI_LOG_ERROR(" mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", impl.mTextUpdateInfo.mEstimatedNumberOfLines);
129 DALI_LOG_ERROR(" mTextUpdateInfo.mClearAll = %d\n", impl.mTextUpdateInfo.mClearAll);
130 DALI_LOG_ERROR(" mTextUpdateInfo.mFullRelayoutNeeded = %d\n", impl.mTextUpdateInfo.mFullRelayoutNeeded);
131 DALI_LOG_ERROR(" mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", impl.mTextUpdateInfo.mIsLastCharacterNewParagraph);
137 startIndex = impl.mTextUpdateInfo.mParagraphCharacterIndex;
139 if(impl.mTextUpdateInfo.mClearAll ||
140 (0u != paragraphCharacters))
142 impl.ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
145 impl.mTextUpdateInfo.mClearAll = false;
147 // Whether the model is updated.
148 bool updated = false;
150 Vector<LineBreakInfo>& lineBreakInfo = impl.mModel->mLogicalModel->mLineBreakInfo;
151 const Length requestedNumberOfCharacters = impl.mTextUpdateInfo.mRequestedNumberOfCharacters;
153 if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
155 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
156 // calculate the bidirectional info for each 'paragraph'.
157 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
158 // is not shaped together).
159 lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
161 SetLineBreakInfo(utf32Characters,
163 requestedNumberOfCharacters,
166 if(impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
167 impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
169 CharacterIndex end = startIndex + requestedNumberOfCharacters;
170 LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
172 for(CharacterIndex index = startIndex; index < end; index++)
174 CharacterIndex wordEnd = index;
175 while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
180 if((wordEnd + 1) == end) // add last char
185 Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
187 for(CharacterIndex i = 0; i < (wordEnd - index); i++)
191 *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
199 // Create the paragraph info.
200 impl.mModel->mLogicalModel->CreateParagraphInfo(startIndex,
201 requestedNumberOfCharacters);
205 const bool getScripts = Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations);
206 const bool validateFonts = Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations);
208 Vector<ScriptRun>& scripts = impl.mModel->mLogicalModel->mScriptRuns;
209 Vector<FontRun>& validFonts = impl.mModel->mLogicalModel->mFontRuns;
211 if(getScripts || validateFonts)
213 // Validates the fonts assigned by the application or assigns default ones.
214 // It makes sure all the characters are going to be rendered by the correct font.
215 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
219 // Retrieves the scripts used in the text.
220 multilanguageSupport.SetScripts(utf32Characters,
222 requestedNumberOfCharacters,
228 // Validate the fonts set through the mark-up string.
229 Vector<FontDescriptionRun>& fontDescriptionRuns = impl.mModel->mLogicalModel->mFontDescriptionRuns;
231 // Get the default font's description.
232 TextAbstraction::FontDescription defaultFontDescription;
233 TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * impl.GetFontSizeScale();
235 //Get the number of points per one unit of point-size
236 uint32_t numberOfPointsPerOneUnitOfPointSize = impl.mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
238 if(impl.IsShowingPlaceholderText() && impl.mEventData && (nullptr != impl.mEventData->mPlaceholderFont))
240 // If the placeholder font is set specifically, only placeholder font is changed.
241 defaultFontDescription = impl.mEventData->mPlaceholderFont->mFontDescription;
242 if(impl.mEventData->mPlaceholderFont->sizeDefined)
244 defaultPointSize = impl.mEventData->mPlaceholderFont->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
247 else if(nullptr != impl.mFontDefaults)
249 // Set the normal font and the placeholder font.
250 defaultFontDescription = impl.mFontDefaults->mFontDescription;
252 if(impl.mTextFitEnabled)
254 defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
258 defaultPointSize = impl.mFontDefaults->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
262 // Validates the fonts. If there is a character with no assigned font it sets a default one.
263 // After this call, fonts are validated.
264 multilanguageSupport.ValidateFonts(utf32Characters,
267 defaultFontDescription,
269 impl.GetFontSizeScale(),
271 requestedNumberOfCharacters,
277 Vector<Character> mirroredUtf32Characters;
278 bool textMirrored = false;
279 const Length numberOfParagraphs = impl.mModel->mLogicalModel->mParagraphInfo.Count();
280 if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
282 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = impl.mModel->mLogicalModel->mBidirectionalParagraphInfo;
283 bidirectionalInfo.Reserve(numberOfParagraphs);
285 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
286 SetBidirectionalInfo(utf32Characters,
290 requestedNumberOfCharacters,
292 (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
293 impl.mLayoutDirection);
295 if(0u != bidirectionalInfo.Count())
297 // Only set the character directions if there is right to left characters.
298 Vector<CharacterDirection>& directions = impl.mModel->mLogicalModel->mCharacterDirections;
299 GetCharactersDirection(bidirectionalInfo,
302 requestedNumberOfCharacters,
305 // This paragraph has right to left text. Some characters may need to be mirrored.
306 // TODO: consider if the mirrored string can be stored as well.
308 textMirrored = GetMirroredText(utf32Characters,
312 requestedNumberOfCharacters,
313 mirroredUtf32Characters);
317 // There is no right to left characters. Clear the directions vector.
318 impl.mModel->mLogicalModel->mCharacterDirections.Clear();
323 Vector<GlyphInfo>& glyphs = impl.mModel->mVisualModel->mGlyphs;
324 Vector<CharacterIndex>& glyphsToCharactersMap = impl.mModel->mVisualModel->mGlyphsToCharacters;
325 Vector<Length>& charactersPerGlyph = impl.mModel->mVisualModel->mCharactersPerGlyph;
326 Vector<GlyphIndex> newParagraphGlyphs;
327 newParagraphGlyphs.Reserve(numberOfParagraphs);
329 const Length currentNumberOfGlyphs = glyphs.Count();
330 if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
332 const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
334 ShapeText(textToShape,
339 impl.mTextUpdateInfo.mStartGlyphIndex,
340 requestedNumberOfCharacters,
342 glyphsToCharactersMap,
346 // Create the 'number of glyphs' per character and the glyph to character conversion tables.
347 impl.mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
348 impl.mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
353 const Length numberOfGlyphs = static_cast<Length>(glyphs.Count()) - currentNumberOfGlyphs;
355 if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
357 GlyphInfo* glyphsBuffer = glyphs.Begin();
358 impl.mMetrics->GetGlyphMetrics(glyphsBuffer + impl.mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
360 // Update the width and advance of all new paragraph characters.
361 for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
363 const GlyphIndex index = *it;
364 GlyphInfo& glyph = *(glyphsBuffer + index);
366 glyph.xBearing = 0.f;
373 if((nullptr != impl.mEventData) &&
374 impl.mEventData->mPreEditFlag &&
375 (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
377 Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
378 impl.mEventData->mInputMethodContext.GetPreeditStyle(attrs);
379 Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
381 // Check the type of preedit and run it.
382 for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
384 Dali::InputMethodContext::PreeditAttributeData attrData = *it;
385 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
386 type = attrData.preeditType;
388 // Check the number of commit characters for the start position.
389 unsigned int numberOfCommit = impl.mEventData->mPrimaryCursorPosition - impl.mEventData->mPreEditLength;
390 Length numberOfIndices = attrData.endIndex - attrData.startIndex;
394 case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
396 // Add the underline for the pre-edit text.
397 UnderlinedGlyphRun underlineRun;
398 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
399 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
400 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
402 //Mark-up processor case
403 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
404 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
406 impl.CopyUnderlinedFromLogicalToVisualModels(false);
410 case Dali::InputMethodContext::PreeditStyle::REVERSE:
412 Vector4 textColor = impl.mModel->mVisualModel->GetTextColor();
413 ColorRun backgroundColorRun;
414 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
415 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
416 backgroundColorRun.color = textColor;
417 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
419 Vector4 backgroundColor = impl.mModel->mVisualModel->GetBackgroundColor();
420 if(Dali::EqualsZero(backgroundColor.a)) // There is no text background color.
422 // Try use the control's background color.
423 if(nullptr != impl.mEditableControlInterface)
425 impl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
426 if(Dali::EqualsZero(backgroundColor.a)) // There is no control background color.
428 // Determines black or white color according to text color.
429 // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
430 float L = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
431 backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
436 Vector<ColorRun> colorRuns;
437 colorRuns.Resize(1u);
438 ColorRun& colorRun = *(colorRuns.Begin());
439 colorRun.color = backgroundColor;
440 colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
441 colorRun.characterRun.numberOfCharacters = numberOfIndices;
442 impl.mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
444 //Mark-up processor case
445 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
446 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
448 impl.CopyUnderlinedFromLogicalToVisualModels(false);
452 case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
454 ColorRun backgroundColorRun;
455 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
456 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
457 backgroundColorRun.color = LIGHT_BLUE;
458 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
460 //Mark-up processor case
461 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
462 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
464 impl.CopyUnderlinedFromLogicalToVisualModels(false);
468 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
470 // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
471 ColorRun backgroundColorRun;
472 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
473 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
474 backgroundColorRun.color = BACKGROUND_SUB4;
475 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
477 UnderlinedGlyphRun underlineRun;
478 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
479 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
480 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
482 //Mark-up processor case
483 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
484 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
486 impl.CopyUnderlinedFromLogicalToVisualModels(false);
490 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
492 // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
493 ColorRun backgroundColorRun;
494 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
495 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
496 backgroundColorRun.color = BACKGROUND_SUB5;
497 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
499 UnderlinedGlyphRun underlineRun;
500 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
501 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
502 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
504 //Mark-up processor case
505 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
506 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
508 impl.CopyUnderlinedFromLogicalToVisualModels(false);
512 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
514 // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
515 ColorRun backgroundColorRun;
516 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
517 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
518 backgroundColorRun.color = BACKGROUND_SUB6;
519 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
521 UnderlinedGlyphRun underlineRun;
522 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
523 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
524 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
526 //Mark-up processor case
527 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
528 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
530 impl.CopyUnderlinedFromLogicalToVisualModels(false);
534 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
536 // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
537 ColorRun backgroundColorRun;
538 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
539 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
540 backgroundColorRun.color = BACKGROUND_SUB7;
541 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
543 UnderlinedGlyphRun underlineRun;
544 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
545 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
546 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
548 //Mark-up processor case
549 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
550 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
552 impl.CopyUnderlinedFromLogicalToVisualModels(false);
556 case Dali::InputMethodContext::PreeditStyle::NONE:
567 if(Controller::NO_OPERATION != (Controller::COLOR & operations))
569 // Set the color runs in glyphs.
570 SetColorSegmentationInfo(impl.mModel->mLogicalModel->mColorRuns,
571 impl.mModel->mVisualModel->mCharactersToGlyph,
572 impl.mModel->mVisualModel->mGlyphsPerCharacter,
574 impl.mTextUpdateInfo.mStartGlyphIndex,
575 requestedNumberOfCharacters,
576 impl.mModel->mVisualModel->mColors,
577 impl.mModel->mVisualModel->mColorIndices);
579 // Set the background color runs in glyphs.
580 SetColorSegmentationInfo(impl.mModel->mLogicalModel->mBackgroundColorRuns,
581 impl.mModel->mVisualModel->mCharactersToGlyph,
582 impl.mModel->mVisualModel->mGlyphsPerCharacter,
584 impl.mTextUpdateInfo.mStartGlyphIndex,
585 requestedNumberOfCharacters,
586 impl.mModel->mVisualModel->mBackgroundColors,
587 impl.mModel->mVisualModel->mBackgroundColorIndices);
592 if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
593 !((nullptr != impl.mEventData) &&
594 impl.mEventData->mPreEditFlag &&
595 (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count())))
597 //Mark-up processor case
598 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
599 impl.mModel->mLogicalModel->mUnderlineRunsUpdated ||
600 impl.mModel->mLogicalModel->mCharacterSpacingRunsUpdated ||
601 impl.mModel->mLogicalModel->mStrikethroughRunsUpdated)
603 impl.CopyUnderlinedFromLogicalToVisualModels(true);
604 impl.CopyStrikethroughFromLogicalToVisualModels();
605 impl.CopyCharacterSpacingFromLogicalToVisualModels();
611 // The estimated number of lines. Used to avoid reallocations when layouting.
612 impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
614 // Set the previous number of characters for the next time the text is updated.
615 impl.mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
620 } // namespace Dali::Toolkit::Text