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 #if defined(TRACE_ENABLED)
47 uint32_t GetMilliSeconds()
49 // Get the time of a monotonic clock since its epoch.
50 auto epoch = std::chrono::steady_clock::now().time_since_epoch();
52 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
54 return static_cast<uint32_t>(duration.count());
58 // The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
59 // based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
60 constexpr float BRIGHTNESS_THRESHOLD = 0.179f;
61 constexpr float CONSTANT_R = 0.2126f;
62 constexpr float CONSTANT_G = 0.7152f;
63 constexpr float CONSTANT_B = 0.0722f;
64 constexpr Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
65 constexpr Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
66 constexpr Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
67 constexpr Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
68 constexpr Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
69 constexpr Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
70 constexpr Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
73 bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask operationsRequired)
75 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
77 // Calculate the operations to be done.
78 const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
80 if(Controller::NO_OPERATION == operations)
82 // Nothing to do if no operations are pending and required.
85 DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_MODEL_UPDATE");
87 Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
88 Vector<Character> displayCharacters;
89 bool useHiddenText = false;
90 if(impl.mHiddenInput && impl.mEventData != nullptr)
92 if(impl.mEventData->mIsShowingPlaceholderText)
94 impl.mHiddenInput->InitPreviousTextCount();
98 impl.mHiddenInput->Substitute(srcCharacters, displayCharacters, impl.mEventData->mPrimaryCursorPosition);
103 Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
104 const Length numberOfCharacters = utf32Characters.Count();
106 // Index to the first character of the first paragraph to be updated.
107 CharacterIndex startIndex = 0u;
108 // Number of characters of the paragraphs to be removed.
109 Length paragraphCharacters = 0u;
111 impl.CalculateTextUpdateIndices(paragraphCharacters);
113 // Check whether the indices for updating the text is valid
114 if(impl.mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
115 impl.mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters)
117 if(numberOfCharacters == 0u)
119 impl.mTextUpdateInfo.Clear();
120 impl.mTextUpdateInfo.mClearAll = true;
122 else // numberOfCharacters > 0u
124 std::string currentText;
125 Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
127 DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
128 DALI_LOG_ERROR("Number of characters: %d, current text is: %s paragraphCharacters: %d\n", numberOfCharacters, currentText.c_str(), paragraphCharacters);
130 // Dump mTextUpdateInfo
131 DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
132 DALI_LOG_ERROR(" mTextUpdateInfo.mCharacterIndex = %u\n", impl.mTextUpdateInfo.mCharacterIndex);
133 DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToRemove);
134 DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToAdd);
135 DALI_LOG_ERROR(" mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mPreviousNumberOfCharacters);
136 DALI_LOG_ERROR(" mTextUpdateInfo.mParagraphCharacterIndex = %u\n", impl.mTextUpdateInfo.mParagraphCharacterIndex);
137 DALI_LOG_ERROR(" mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mRequestedNumberOfCharacters);
138 DALI_LOG_ERROR(" mTextUpdateInfo.mStartGlyphIndex = %u\n", impl.mTextUpdateInfo.mStartGlyphIndex);
139 DALI_LOG_ERROR(" mTextUpdateInfo.mStartLineIndex = %u\n", impl.mTextUpdateInfo.mStartLineIndex);
140 DALI_LOG_ERROR(" mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", impl.mTextUpdateInfo.mEstimatedNumberOfLines);
141 DALI_LOG_ERROR(" mTextUpdateInfo.mClearAll = %d\n", impl.mTextUpdateInfo.mClearAll);
142 DALI_LOG_ERROR(" mTextUpdateInfo.mFullRelayoutNeeded = %d\n", impl.mTextUpdateInfo.mFullRelayoutNeeded);
143 DALI_LOG_ERROR(" mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", impl.mTextUpdateInfo.mIsLastCharacterNewParagraph);
149 startIndex = impl.mTextUpdateInfo.mParagraphCharacterIndex;
151 if(impl.mTextUpdateInfo.mClearAll ||
152 (0u != paragraphCharacters))
154 impl.ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
157 impl.mTextUpdateInfo.mClearAll = false;
159 // Whether the model is updated.
160 bool updated = false;
162 Vector<LineBreakInfo>& lineBreakInfo = impl.mModel->mLogicalModel->mLineBreakInfo;
163 const Length requestedNumberOfCharacters = impl.mTextUpdateInfo.mRequestedNumberOfCharacters;
165 if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
167 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
168 // calculate the bidirectional info for each 'paragraph'.
169 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
170 // is not shaped together).
171 lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
173 SetLineBreakInfo(utf32Characters,
175 requestedNumberOfCharacters,
178 if(impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
179 impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
181 CharacterIndex end = startIndex + requestedNumberOfCharacters;
182 LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
184 for(CharacterIndex index = startIndex; index < end; index++)
186 CharacterIndex wordEnd = index;
187 while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
192 if((wordEnd + 1) == end) // add last char
197 Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
199 for(CharacterIndex i = 0; i < (wordEnd - index); i++)
203 *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
211 // Create the paragraph info.
212 impl.mModel->mLogicalModel->CreateParagraphInfo(startIndex,
213 requestedNumberOfCharacters);
217 const bool getScripts = Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations);
218 const bool validateFonts = Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations);
220 Vector<ScriptRun>& scripts = impl.mModel->mLogicalModel->mScriptRuns;
221 Vector<FontRun>& validFonts = impl.mModel->mLogicalModel->mFontRuns;
223 if(getScripts || validateFonts)
225 // Validates the fonts assigned by the application or assigns default ones.
226 // It makes sure all the characters are going to be rendered by the correct font.
227 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
231 // Retrieves the scripts used in the text.
232 multilanguageSupport.SetScripts(utf32Characters,
234 requestedNumberOfCharacters,
240 // Validate the fonts set through the mark-up string.
241 Vector<FontDescriptionRun>& fontDescriptionRuns = impl.mModel->mLogicalModel->mFontDescriptionRuns;
243 // Get the default font's description.
244 TextAbstraction::FontDescription defaultFontDescription;
245 TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * impl.GetFontSizeScale();
247 //Get the number of points per one unit of point-size
248 uint32_t numberOfPointsPerOneUnitOfPointSize = impl.mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
250 if(impl.IsShowingPlaceholderText() && impl.mEventData && (nullptr != impl.mEventData->mPlaceholderFont))
252 // If the placeholder font is set specifically, only placeholder font is changed.
253 defaultFontDescription = impl.mEventData->mPlaceholderFont->mFontDescription;
254 if(impl.mEventData->mPlaceholderFont->sizeDefined)
256 defaultPointSize = impl.mEventData->mPlaceholderFont->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
259 else if(nullptr != impl.mFontDefaults)
261 // Set the normal font and the placeholder font.
262 defaultFontDescription = impl.mFontDefaults->mFontDescription;
264 if(impl.mTextFitEnabled)
266 defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
270 defaultPointSize = impl.mFontDefaults->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
274 // Validates the fonts. If there is a character with no assigned font it sets a default one.
275 // After this call, fonts are validated.
276 multilanguageSupport.ValidateFonts(utf32Characters,
279 defaultFontDescription,
281 impl.GetFontSizeScale(),
283 requestedNumberOfCharacters,
289 Vector<Character> mirroredUtf32Characters;
290 bool textMirrored = false;
291 const Length numberOfParagraphs = impl.mModel->mLogicalModel->mParagraphInfo.Count();
292 if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
294 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = impl.mModel->mLogicalModel->mBidirectionalParagraphInfo;
295 bidirectionalInfo.Reserve(numberOfParagraphs);
297 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
298 SetBidirectionalInfo(utf32Characters,
302 requestedNumberOfCharacters,
304 (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
305 impl.mLayoutDirection);
307 if(0u != bidirectionalInfo.Count())
309 // Only set the character directions if there is right to left characters.
310 Vector<CharacterDirection>& directions = impl.mModel->mLogicalModel->mCharacterDirections;
311 GetCharactersDirection(bidirectionalInfo,
314 requestedNumberOfCharacters,
317 // This paragraph has right to left text. Some characters may need to be mirrored.
318 // TODO: consider if the mirrored string can be stored as well.
320 textMirrored = GetMirroredText(utf32Characters,
324 requestedNumberOfCharacters,
325 mirroredUtf32Characters);
329 // There is no right to left characters. Clear the directions vector.
330 impl.mModel->mLogicalModel->mCharacterDirections.Clear();
335 Vector<GlyphInfo>& glyphs = impl.mModel->mVisualModel->mGlyphs;
336 Vector<CharacterIndex>& glyphsToCharactersMap = impl.mModel->mVisualModel->mGlyphsToCharacters;
337 Vector<Length>& charactersPerGlyph = impl.mModel->mVisualModel->mCharactersPerGlyph;
338 Vector<GlyphIndex> newParagraphGlyphs;
339 newParagraphGlyphs.Reserve(numberOfParagraphs);
341 const Length currentNumberOfGlyphs = glyphs.Count();
343 #if defined(TRACE_ENABLED)
344 uint32_t logThreshold = TextAbstraction::FontClient::GetPerformanceLogThresholdTime();
345 bool logEnabled = TextAbstraction::FontClient::IsPerformanceLogEnabled();
347 uint32_t timeStamps[6];
348 uint32_t timeStampIndex = 0;
352 timeStamps[timeStampIndex++] = GetMilliSeconds();
356 if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
358 const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
360 ShapeText(textToShape,
365 impl.mTextUpdateInfo.mStartGlyphIndex,
366 requestedNumberOfCharacters,
368 glyphsToCharactersMap,
372 // Create the 'number of glyphs' per character and the glyph to character conversion tables.
373 impl.mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
374 impl.mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
379 #if defined(TRACE_ENABLED)
382 timeStamps[timeStampIndex++] = GetMilliSeconds();
386 const Length numberOfGlyphs = static_cast<Length>(glyphs.Count()) - currentNumberOfGlyphs;
388 if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
390 GlyphInfo* glyphsBuffer = glyphs.Begin();
391 impl.mMetrics->GetGlyphMetrics(glyphsBuffer + impl.mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
393 // Update the width and advance of all new paragraph characters.
394 for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
396 const GlyphIndex index = *it;
397 GlyphInfo& glyph = *(glyphsBuffer + index);
399 glyph.xBearing = 0.f;
406 #if defined(TRACE_ENABLED)
409 timeStamps[timeStampIndex++] = GetMilliSeconds();
413 if((nullptr != impl.mEventData) &&
414 impl.mEventData->mPreEditFlag &&
415 (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
417 Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
418 impl.mEventData->mInputMethodContext.GetPreeditStyle(attrs);
419 Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
421 // Check the type of preedit and run it.
422 for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
424 Dali::InputMethodContext::PreeditAttributeData attrData = *it;
425 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
426 type = attrData.preeditType;
428 // Check the number of commit characters for the start position.
429 unsigned int numberOfCommit = impl.mEventData->mPrimaryCursorPosition - impl.mEventData->mPreEditLength;
430 Length numberOfIndices = attrData.endIndex - attrData.startIndex;
434 case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
436 // Add the underline for the pre-edit text.
437 UnderlinedGlyphRun underlineRun;
438 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
439 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
440 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
442 //Mark-up processor case
443 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
444 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
446 impl.CopyUnderlinedFromLogicalToVisualModels(false);
450 case Dali::InputMethodContext::PreeditStyle::REVERSE:
452 Vector4 textColor = impl.mModel->mVisualModel->GetTextColor();
453 ColorRun backgroundColorRun;
454 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
455 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
456 backgroundColorRun.color = textColor;
457 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
459 Vector4 backgroundColor = impl.mModel->mVisualModel->GetBackgroundColor();
460 if(Dali::EqualsZero(backgroundColor.a)) // There is no text background color.
462 // Try use the control's background color.
463 if(nullptr != impl.mEditableControlInterface)
465 impl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
466 if(Dali::EqualsZero(backgroundColor.a)) // There is no control background color.
468 // Determines black or white color according to text color.
469 // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
470 float L = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
471 backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
476 Vector<ColorRun> colorRuns;
477 colorRuns.Resize(1u);
478 ColorRun& colorRun = *(colorRuns.Begin());
479 colorRun.color = backgroundColor;
480 colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
481 colorRun.characterRun.numberOfCharacters = numberOfIndices;
482 impl.mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
484 //Mark-up processor case
485 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
486 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
488 impl.CopyUnderlinedFromLogicalToVisualModels(false);
492 case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
494 ColorRun backgroundColorRun;
495 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
496 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
497 backgroundColorRun.color = LIGHT_BLUE;
498 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
500 //Mark-up processor case
501 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
502 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
504 impl.CopyUnderlinedFromLogicalToVisualModels(false);
508 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
510 // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
511 ColorRun backgroundColorRun;
512 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
513 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
514 backgroundColorRun.color = BACKGROUND_SUB4;
515 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
517 UnderlinedGlyphRun underlineRun;
518 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
519 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
520 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
522 //Mark-up processor case
523 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
524 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
526 impl.CopyUnderlinedFromLogicalToVisualModels(false);
530 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
532 // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
533 ColorRun backgroundColorRun;
534 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
535 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
536 backgroundColorRun.color = BACKGROUND_SUB5;
537 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
539 UnderlinedGlyphRun underlineRun;
540 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
541 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
542 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
544 //Mark-up processor case
545 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
546 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
548 impl.CopyUnderlinedFromLogicalToVisualModels(false);
552 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
554 // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
555 ColorRun backgroundColorRun;
556 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
557 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
558 backgroundColorRun.color = BACKGROUND_SUB6;
559 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
561 UnderlinedGlyphRun underlineRun;
562 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
563 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
564 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
566 //Mark-up processor case
567 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
568 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
570 impl.CopyUnderlinedFromLogicalToVisualModels(false);
574 case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
576 // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
577 ColorRun backgroundColorRun;
578 backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
579 backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
580 backgroundColorRun.color = BACKGROUND_SUB7;
581 impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
583 UnderlinedGlyphRun underlineRun;
584 underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
585 underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
586 impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
588 //Mark-up processor case
589 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
590 impl.mModel->mLogicalModel->mUnderlineRunsUpdated)
592 impl.CopyUnderlinedFromLogicalToVisualModels(false);
596 case Dali::InputMethodContext::PreeditStyle::NONE:
607 #if defined(TRACE_ENABLED)
610 timeStamps[timeStampIndex++] = GetMilliSeconds();
614 if(Controller::NO_OPERATION != (Controller::COLOR & operations))
616 // Set the color runs in glyphs.
617 SetColorSegmentationInfo(impl.mModel->mLogicalModel->mColorRuns,
618 impl.mModel->mVisualModel->mCharactersToGlyph,
619 impl.mModel->mVisualModel->mGlyphsPerCharacter,
621 impl.mTextUpdateInfo.mStartGlyphIndex,
622 requestedNumberOfCharacters,
623 impl.mModel->mVisualModel->mColors,
624 impl.mModel->mVisualModel->mColorIndices);
626 // Set the background color runs in glyphs.
627 SetColorSegmentationInfo(impl.mModel->mLogicalModel->mBackgroundColorRuns,
628 impl.mModel->mVisualModel->mCharactersToGlyph,
629 impl.mModel->mVisualModel->mGlyphsPerCharacter,
631 impl.mTextUpdateInfo.mStartGlyphIndex,
632 requestedNumberOfCharacters,
633 impl.mModel->mVisualModel->mBackgroundColors,
634 impl.mModel->mVisualModel->mBackgroundColorIndices);
639 #if defined(TRACE_ENABLED)
642 timeStamps[timeStampIndex++] = GetMilliSeconds();
646 if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
647 !((nullptr != impl.mEventData) &&
648 impl.mEventData->mPreEditFlag &&
649 (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count())))
651 //Mark-up processor case
652 if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled() ||
653 impl.mModel->mLogicalModel->mUnderlineRunsUpdated ||
654 impl.mModel->mLogicalModel->mCharacterSpacingRunsUpdated ||
655 impl.mModel->mLogicalModel->mStrikethroughRunsUpdated)
657 impl.CopyUnderlinedFromLogicalToVisualModels(true);
658 impl.CopyStrikethroughFromLogicalToVisualModels();
659 impl.CopyCharacterSpacingFromLogicalToVisualModels();
665 #if defined(TRACE_ENABLED)
668 timeStamps[timeStampIndex++] = GetMilliSeconds();
669 uint32_t timeShape = timeStamps[1] - timeStamps[0];
670 uint32_t timeGlyph = timeStamps[2] - timeStamps[1];
671 uint32_t timePreedit = timeStamps[3] - timeStamps[2];
672 uint32_t timeColor = timeStamps[4] - timeStamps[3];
673 uint32_t timeCopy = timeStamps[5] - timeStamps[4];
675 if(timeStamps[5] - timeStamps[0] > logThreshold)
677 std::string currentText;
678 Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
679 DALI_LOG_DEBUG_INFO("DALI_TEXT_MODEL_UPDATE shape:%u ms, glyph:%u ms, preedit:%u ms, color:%u ms, copy:%u ms\n", timeShape, timeGlyph, timePreedit, timeColor, timeCopy);
680 DALI_LOG_DEBUG_INFO("DALI_TEXT_MODEL_UPDATE chars:%d, text:%s\n", numberOfCharacters, currentText.c_str());
685 // The estimated number of lines. Used to avoid reallocations when layouting.
686 impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
688 // Set the previous number of characters for the next time the text is updated.
689 impl.mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
694 } // namespace Dali::Toolkit::Text