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