Merge "Use Renderer::BlendMode::USE_ACTOR_OPACITY instead to use depth write mode...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / controller / text-controller-impl-model-updater.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/controller/text-controller-impl-model-updater.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/math/math-utils.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/internal/text/bidirectional-support.h>
27 #include <dali-toolkit/internal/text/character-set-conversion.h>
28 #include <dali-toolkit/internal/text/color-segmentation.h>
29 #include <dali-toolkit/internal/text/hyphenator.h>
30 #include <dali-toolkit/internal/text/multi-language-support.h>
31 #include <dali-toolkit/internal/text/segmentation.h>
32 #include <dali-toolkit/internal/text/shaper.h>
33 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
34
35 namespace Dali::Toolkit::Text
36 {
37 namespace
38 {
39 #if defined(DEBUG_ENABLED)
40 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
41 #endif
42
43 // The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
44 // based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
45 constexpr float         BRIGHTNESS_THRESHOLD = 0.179f;
46 constexpr float         CONSTANT_R           = 0.2126f;
47 constexpr float         CONSTANT_G           = 0.7152f;
48 constexpr float         CONSTANT_B           = 0.0722f;
49 constexpr Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
50 constexpr Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
51 constexpr Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
52 constexpr Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
53 constexpr Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
54 constexpr Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
55 constexpr Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
56 } // namespace
57
58 bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask operationsRequired)
59 {
60   DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
61
62   // Calculate the operations to be done.
63   const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
64
65   if(Controller::NO_OPERATION == operations)
66   {
67     // Nothing to do if no operations are pending and required.
68     return false;
69   }
70
71   Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
72   Vector<Character>  displayCharacters;
73   bool               useHiddenText = false;
74   if(impl.mHiddenInput && impl.mEventData != nullptr)
75   {
76     if(impl.mEventData->mIsShowingPlaceholderText)
77     {
78       impl.mHiddenInput->InitPreviousTextCount();
79     }
80     else
81     {
82       impl.mHiddenInput->Substitute(srcCharacters, displayCharacters, impl.mEventData->mPrimaryCursorPosition);
83       useHiddenText = true;
84     }
85   }
86
87   Vector<Character>& utf32Characters    = useHiddenText ? displayCharacters : srcCharacters;
88   const Length       numberOfCharacters = utf32Characters.Count();
89
90   // Index to the first character of the first paragraph to be updated.
91   CharacterIndex startIndex = 0u;
92   // Number of characters of the paragraphs to be removed.
93   Length paragraphCharacters = 0u;
94
95   impl.CalculateTextUpdateIndices(paragraphCharacters);
96
97   // Check whether the indices for updating the text is valid
98   if(numberOfCharacters > 0u &&
99      (impl.mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
100       impl.mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
101   {
102     std::string currentText;
103     Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
104
105     DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
106     DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
107
108     // Dump mTextUpdateInfo
109     DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
110     DALI_LOG_ERROR("     mTextUpdateInfo.mCharacterIndex = %u\n", impl.mTextUpdateInfo.mCharacterIndex);
111     DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToRemove);
112     DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToAdd);
113     DALI_LOG_ERROR("     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mPreviousNumberOfCharacters);
114     DALI_LOG_ERROR("     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", impl.mTextUpdateInfo.mParagraphCharacterIndex);
115     DALI_LOG_ERROR("     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mRequestedNumberOfCharacters);
116     DALI_LOG_ERROR("     mTextUpdateInfo.mStartGlyphIndex = %u\n", impl.mTextUpdateInfo.mStartGlyphIndex);
117     DALI_LOG_ERROR("     mTextUpdateInfo.mStartLineIndex = %u\n", impl.mTextUpdateInfo.mStartLineIndex);
118     DALI_LOG_ERROR("     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", impl.mTextUpdateInfo.mEstimatedNumberOfLines);
119     DALI_LOG_ERROR("     mTextUpdateInfo.mClearAll = %d\n", impl.mTextUpdateInfo.mClearAll);
120     DALI_LOG_ERROR("     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", impl.mTextUpdateInfo.mFullRelayoutNeeded);
121     DALI_LOG_ERROR("     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", impl.mTextUpdateInfo.mIsLastCharacterNewParagraph);
122
123     return false;
124   }
125
126   startIndex = impl.mTextUpdateInfo.mParagraphCharacterIndex;
127
128   if(impl.mTextUpdateInfo.mClearAll ||
129      (0u != paragraphCharacters))
130   {
131     impl.ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
132   }
133
134   impl.mTextUpdateInfo.mClearAll = false;
135
136   // Whether the model is updated.
137   bool updated = false;
138
139   Vector<LineBreakInfo>& lineBreakInfo               = impl.mModel->mLogicalModel->mLineBreakInfo;
140   const Length           requestedNumberOfCharacters = impl.mTextUpdateInfo.mRequestedNumberOfCharacters;
141
142   if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
143   {
144     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
145     // calculate the bidirectional info for each 'paragraph'.
146     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
147     // is not shaped together).
148     lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
149
150     SetLineBreakInfo(utf32Characters,
151                      startIndex,
152                      requestedNumberOfCharacters,
153                      lineBreakInfo);
154
155     if(impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
156        impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
157     {
158       CharacterIndex end                 = startIndex + requestedNumberOfCharacters;
159       LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
160
161       for(CharacterIndex index = startIndex; index < end; index++)
162       {
163         CharacterIndex wordEnd = index;
164         while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
165         {
166           wordEnd++;
167         }
168
169         if((wordEnd + 1) == end) // add last char
170         {
171           wordEnd++;
172         }
173
174         Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
175
176         for(CharacterIndex i = 0; i < (wordEnd - index); i++)
177         {
178           if(hyphens[i])
179           {
180             *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
181           }
182         }
183
184         index = wordEnd;
185       }
186     }
187
188     // Create the paragraph info.
189     impl.mModel->mLogicalModel->CreateParagraphInfo(startIndex,
190                                                     requestedNumberOfCharacters);
191     updated = true;
192   }
193
194   const bool getScripts    = Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations);
195   const bool validateFonts = Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations);
196
197   Vector<ScriptRun>& scripts    = impl.mModel->mLogicalModel->mScriptRuns;
198   Vector<FontRun>&   validFonts = impl.mModel->mLogicalModel->mFontRuns;
199
200   if(getScripts || validateFonts)
201   {
202     // Validates the fonts assigned by the application or assigns default ones.
203     // It makes sure all the characters are going to be rendered by the correct font.
204     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
205
206     if(getScripts)
207     {
208       // Retrieves the scripts used in the text.
209       multilanguageSupport.SetScripts(utf32Characters,
210                                       startIndex,
211                                       requestedNumberOfCharacters,
212                                       scripts);
213     }
214
215     if(validateFonts)
216     {
217       // Validate the fonts set through the mark-up string.
218       Vector<FontDescriptionRun>& fontDescriptionRuns = impl.mModel->mLogicalModel->mFontDescriptionRuns;
219
220       // Get the default font's description.
221       TextAbstraction::FontDescription defaultFontDescription;
222       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * impl.GetFontSizeScale();
223
224       //Get the number of points per one unit of point-size
225       uint32_t numberOfPointsPerOneUnitOfPointSize = impl.mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
226
227       if(impl.IsShowingPlaceholderText() && impl.mEventData && (nullptr != impl.mEventData->mPlaceholderFont))
228       {
229         // If the placeholder font is set specifically, only placeholder font is changed.
230         defaultFontDescription = impl.mEventData->mPlaceholderFont->mFontDescription;
231         if(impl.mEventData->mPlaceholderFont->sizeDefined)
232         {
233           defaultPointSize = impl.mEventData->mPlaceholderFont->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
234         }
235       }
236       else if(nullptr != impl.mFontDefaults)
237       {
238         // Set the normal font and the placeholder font.
239         defaultFontDescription = impl.mFontDefaults->mFontDescription;
240
241         if(impl.mTextFitEnabled)
242         {
243           defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
244         }
245         else
246         {
247           defaultPointSize = impl.mFontDefaults->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
248         }
249       }
250
251       // Validates the fonts. If there is a character with no assigned font it sets a default one.
252       // After this call, fonts are validated.
253       multilanguageSupport.ValidateFonts(utf32Characters,
254                                          scripts,
255                                          fontDescriptionRuns,
256                                          defaultFontDescription,
257                                          defaultPointSize,
258                                          startIndex,
259                                          requestedNumberOfCharacters,
260                                          validFonts);
261     }
262     updated = true;
263   }
264
265   Vector<Character> mirroredUtf32Characters;
266   bool              textMirrored       = false;
267   const Length      numberOfParagraphs = impl.mModel->mLogicalModel->mParagraphInfo.Count();
268   if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
269   {
270     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = impl.mModel->mLogicalModel->mBidirectionalParagraphInfo;
271     bidirectionalInfo.Reserve(numberOfParagraphs);
272
273     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
274     SetBidirectionalInfo(utf32Characters,
275                          scripts,
276                          lineBreakInfo,
277                          startIndex,
278                          requestedNumberOfCharacters,
279                          bidirectionalInfo,
280                          (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
281                          impl.mLayoutDirection);
282
283     if(0u != bidirectionalInfo.Count())
284     {
285       // Only set the character directions if there is right to left characters.
286       Vector<CharacterDirection>& directions = impl.mModel->mLogicalModel->mCharacterDirections;
287       GetCharactersDirection(bidirectionalInfo,
288                              numberOfCharacters,
289                              startIndex,
290                              requestedNumberOfCharacters,
291                              directions);
292
293       // This paragraph has right to left text. Some characters may need to be mirrored.
294       // TODO: consider if the mirrored string can be stored as well.
295
296       textMirrored = GetMirroredText(utf32Characters,
297                                      directions,
298                                      bidirectionalInfo,
299                                      startIndex,
300                                      requestedNumberOfCharacters,
301                                      mirroredUtf32Characters);
302     }
303     else
304     {
305       // There is no right to left characters. Clear the directions vector.
306       impl.mModel->mLogicalModel->mCharacterDirections.Clear();
307     }
308     updated = true;
309   }
310
311   Vector<GlyphInfo>&      glyphs                = impl.mModel->mVisualModel->mGlyphs;
312   Vector<CharacterIndex>& glyphsToCharactersMap = impl.mModel->mVisualModel->mGlyphsToCharacters;
313   Vector<Length>&         charactersPerGlyph    = impl.mModel->mVisualModel->mCharactersPerGlyph;
314   Vector<GlyphIndex>      newParagraphGlyphs;
315   newParagraphGlyphs.Reserve(numberOfParagraphs);
316
317   const Length currentNumberOfGlyphs = glyphs.Count();
318   if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
319   {
320     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
321     // Shapes the text.
322     ShapeText(textToShape,
323               lineBreakInfo,
324               scripts,
325               validFonts,
326               startIndex,
327               impl.mTextUpdateInfo.mStartGlyphIndex,
328               requestedNumberOfCharacters,
329               glyphs,
330               glyphsToCharactersMap,
331               charactersPerGlyph,
332               newParagraphGlyphs);
333
334     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
335     impl.mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
336     impl.mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
337
338     updated = true;
339   }
340
341   const Length numberOfGlyphs = static_cast<Length>(glyphs.Count()) - currentNumberOfGlyphs;
342
343   if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
344   {
345     GlyphInfo* glyphsBuffer = glyphs.Begin();
346     impl.mMetrics->GetGlyphMetrics(glyphsBuffer + impl.mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
347
348     // Update the width and advance of all new paragraph characters.
349     for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
350     {
351       const GlyphIndex index = *it;
352       GlyphInfo&       glyph = *(glyphsBuffer + index);
353
354       glyph.xBearing = 0.f;
355       glyph.width    = 0.f;
356       glyph.advance  = 0.f;
357     }
358     updated = true;
359   }
360
361   if((nullptr != impl.mEventData) &&
362      impl.mEventData->mPreEditFlag &&
363      (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
364   {
365     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
366     impl.mEventData->mInputMethodContext.GetPreeditStyle(attrs);
367     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
368
369     // Check the type of preedit and run it.
370     for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
371     {
372       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
373       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
374       type = attrData.preeditType;
375
376       // Check the number of commit characters for the start position.
377       unsigned int numberOfCommit  = impl.mEventData->mPrimaryCursorPosition - impl.mEventData->mPreEditLength;
378       Length       numberOfIndices = attrData.endIndex - attrData.startIndex;
379
380       switch(type)
381       {
382         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
383         {
384           // Add the underline for the pre-edit text.
385           UnderlinedGlyphRun underlineRun;
386           underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
387           underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
388           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
389
390           //Mark-up processor case
391           if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
392              impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
393           {
394             impl.CopyUnderlinedFromLogicalToVisualModels(false);
395           }
396           break;
397         }
398         case Dali::InputMethodContext::PreeditStyle::REVERSE:
399         {
400           Vector4  textColor = impl.mModel->mVisualModel->GetTextColor();
401           ColorRun backgroundColorRun;
402           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
403           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
404           backgroundColorRun.color                           = textColor;
405           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
406
407           Vector4 backgroundColor = impl.mModel->mVisualModel->GetBackgroundColor();
408           if(Dali::EqualsZero(backgroundColor.a)) // There is no text background color.
409           {
410             // Try use the control's background color.
411             if(nullptr != impl.mEditableControlInterface)
412             {
413               impl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
414               if(Dali::EqualsZero(backgroundColor.a)) // There is no control background color.
415               {
416                 // Determines black or white color according to text color.
417                 // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
418                 float L         = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
419                 backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
420               }
421             }
422           }
423
424           Vector<ColorRun> colorRuns;
425           colorRuns.Resize(1u);
426           ColorRun& colorRun                       = *(colorRuns.Begin());
427           colorRun.color                           = backgroundColor;
428           colorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
429           colorRun.characterRun.numberOfCharacters = numberOfIndices;
430           impl.mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
431
432           //Mark-up processor case
433           if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
434              impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
435           {
436             impl.CopyUnderlinedFromLogicalToVisualModels(false);
437           }
438           break;
439         }
440         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
441         {
442           ColorRun backgroundColorRun;
443           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
444           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
445           backgroundColorRun.color                           = LIGHT_BLUE;
446           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
447
448           //Mark-up processor case
449           if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
450              impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
451           {
452             impl.CopyUnderlinedFromLogicalToVisualModels(false);
453           }
454           break;
455         }
456         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
457         {
458           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
459           ColorRun backgroundColorRun;
460           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
461           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
462           backgroundColorRun.color                           = BACKGROUND_SUB4;
463           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
464
465           UnderlinedGlyphRun underlineRun;
466           underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
467           underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
468           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
469
470           //Mark-up processor case
471           if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
472              impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
473           {
474             impl.CopyUnderlinedFromLogicalToVisualModels(false);
475           }
476           break;
477         }
478         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
479         {
480           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
481           ColorRun backgroundColorRun;
482           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
483           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
484           backgroundColorRun.color                           = BACKGROUND_SUB5;
485           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
486
487           UnderlinedGlyphRun underlineRun;
488           underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
489           underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
490           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
491
492           //Mark-up processor case
493           if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
494              impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
495           {
496             impl.CopyUnderlinedFromLogicalToVisualModels(false);
497           }
498           break;
499         }
500         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
501         {
502           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
503           ColorRun backgroundColorRun;
504           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
505           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
506           backgroundColorRun.color                           = BACKGROUND_SUB6;
507           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
508
509           UnderlinedGlyphRun underlineRun;
510           underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
511           underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
512           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
513
514           //Mark-up processor case
515           if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
516              impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
517           {
518             impl.CopyUnderlinedFromLogicalToVisualModels(false);
519           }
520           break;
521         }
522         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
523         {
524           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
525           ColorRun backgroundColorRun;
526           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
527           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
528           backgroundColorRun.color                           = BACKGROUND_SUB7;
529           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
530
531           UnderlinedGlyphRun underlineRun;
532           underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
533           underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
534           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
535
536           //Mark-up processor case
537           if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
538              impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
539           {
540             impl.CopyUnderlinedFromLogicalToVisualModels(false);
541           }
542           break;
543         }
544         case Dali::InputMethodContext::PreeditStyle::NONE:
545         default:
546         {
547           break;
548         }
549       }
550     }
551     attrs.Clear();
552     updated = true;
553   }
554
555   if(Controller::NO_OPERATION != (Controller::COLOR & operations))
556   {
557     // Set the color runs in glyphs.
558     SetColorSegmentationInfo(impl.mModel->mLogicalModel->mColorRuns,
559                              impl.mModel->mVisualModel->mCharactersToGlyph,
560                              impl.mModel->mVisualModel->mGlyphsPerCharacter,
561                              startIndex,
562                              impl.mTextUpdateInfo.mStartGlyphIndex,
563                              requestedNumberOfCharacters,
564                              impl.mModel->mVisualModel->mColors,
565                              impl.mModel->mVisualModel->mColorIndices);
566
567     // Set the background color runs in glyphs.
568     SetColorSegmentationInfo(impl.mModel->mLogicalModel->mBackgroundColorRuns,
569                              impl.mModel->mVisualModel->mCharactersToGlyph,
570                              impl.mModel->mVisualModel->mGlyphsPerCharacter,
571                              startIndex,
572                              impl.mTextUpdateInfo.mStartGlyphIndex,
573                              requestedNumberOfCharacters,
574                              impl.mModel->mVisualModel->mBackgroundColors,
575                              impl.mModel->mVisualModel->mBackgroundColorIndices);
576
577     updated = true;
578   }
579
580   if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
581      !((nullptr != impl.mEventData) &&
582        impl.mEventData->mPreEditFlag &&
583        (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count())))
584   {
585     //Mark-up processor case
586     if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
587        impl.mModel->mLogicalModel->mUnderlineRunsUpdated ||
588        impl.mModel->mLogicalModel->mCharacterSpacingRunsUpdated ||
589        impl.mModel->mLogicalModel->mStrikethroughRunsUpdated)
590     {
591       impl.CopyUnderlinedFromLogicalToVisualModels(true);
592       impl.CopyStrikethroughFromLogicalToVisualModels();
593       impl.CopyCharacterSpacingFromLogicalToVisualModels();
594     }
595
596     updated = true;
597   }
598
599   // The estimated number of lines. Used to avoid reallocations when layouting.
600   impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
601
602   // Set the previous number of characters for the next time the text is updated.
603   impl.mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
604
605   return updated;
606 }
607
608 } // namespace Dali::Toolkit::Text