// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/internal/text/bidirectional-support.h>
#include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/color-segmentation.h>
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/multi-language-support.h>
-#include <dali-toolkit/internal/text/segmentation.h>
-#include <dali-toolkit/internal/text/shaper.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
#include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
+#include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
#include <dali-toolkit/internal/text/text-run-container.h>
#include <dali-toolkit/internal/text/text-selection-handle-controller.h>
Vector<unsigned short> mIndices; ///< container of indices
};
-const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
-
} // namespace
-namespace Dali
+namespace Dali::Toolkit::Text
{
-namespace Toolkit
+
+namespace
{
-namespace Text
+
+void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const fontDefaults, const Vector4& textColor)
{
+ // Sets the default text's color.
+ inputStyle.textColor = textColor;
+ inputStyle.isDefaultColor = true;
+
+ inputStyle.familyName.clear();
+ inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
+ inputStyle.width = TextAbstraction::FontWidth::NORMAL;
+ inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
+ inputStyle.size = 0.f;
+
+ inputStyle.lineSpacing = 0.f;
+
+ inputStyle.underlineProperties.clear();
+ inputStyle.shadowProperties.clear();
+ inputStyle.embossProperties.clear();
+ inputStyle.outlineProperties.clear();
+
+ inputStyle.isFamilyDefined = false;
+ inputStyle.isWeightDefined = false;
+ inputStyle.isWidthDefined = false;
+ inputStyle.isSlantDefined = false;
+ inputStyle.isSizeDefined = false;
+
+ inputStyle.isLineSpacingDefined = false;
+
+ inputStyle.isUnderlineDefined = false;
+ inputStyle.isShadowDefined = false;
+ inputStyle.isEmbossDefined = false;
+ inputStyle.isOutlineDefined = false;
+
+ // Sets the default font's family name, weight, width, slant and size.
+ if(fontDefaults)
+ {
+ if(fontDefaults->familyDefined)
+ {
+ inputStyle.familyName = fontDefaults->mFontDescription.family;
+ inputStyle.isFamilyDefined = true;
+ }
+
+ if(fontDefaults->weightDefined)
+ {
+ inputStyle.weight = fontDefaults->mFontDescription.weight;
+ inputStyle.isWeightDefined = true;
+ }
+
+ if(fontDefaults->widthDefined)
+ {
+ inputStyle.width = fontDefaults->mFontDescription.width;
+ inputStyle.isWidthDefined = true;
+ }
+
+ if(fontDefaults->slantDefined)
+ {
+ inputStyle.slant = fontDefaults->mFontDescription.slant;
+ inputStyle.isSlantDefined = true;
+ }
+
+ if(fontDefaults->sizeDefined)
+ {
+ inputStyle.size = fontDefaults->mDefaultPointSize;
+ inputStyle.isSizeDefined = true;
+ }
+ }
+}
+} // unnamed Namespace
+
EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
: mDecorator(decorator),
mInputMethodContext(inputMethodContext),
- mPlaceholderFont(NULL),
+ mPlaceholderFont(nullptr),
mPlaceholderTextActive(),
mPlaceholderTextInactive(),
mPlaceholderTextColor(0.8f, 0.8f, 0.8f, 0.8f), // This color has been published in the Public API (placeholder-properties.h).
mModel->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
charactersPerGlyphBuffer + endGlyphIndexPlusOne);
- // Clear the positions buffer.
- Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
- mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
- positionsBuffer + endGlyphIndexPlusOne);
+ // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout
+ if(0u != mModel->mVisualModel->mGlyphPositions.Count())
+ {
+ // Clear the positions buffer.
+ Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
+ mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+ positionsBuffer + endGlyphIndexPlusOne);
+ }
}
if(NO_OPERATION != (LAYOUT & operations))
bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
{
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
-
- // Calculate the operations to be done.
- const OperationsMask operations = static_cast<OperationsMask>(mOperationsPending & operationsRequired);
-
- if(NO_OPERATION == operations)
- {
- // Nothing to do if no operations are pending and required.
- return false;
- }
-
- Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
- Vector<Character> displayCharacters;
- bool useHiddenText = false;
- if(mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
- {
- mHiddenInput->Substitute(srcCharacters, displayCharacters);
- useHiddenText = true;
- }
-
- Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
- const Length numberOfCharacters = utf32Characters.Count();
-
- // Index to the first character of the first paragraph to be updated.
- CharacterIndex startIndex = 0u;
- // Number of characters of the paragraphs to be removed.
- Length paragraphCharacters = 0u;
-
- CalculateTextUpdateIndices(paragraphCharacters);
-
- // Check whether the indices for updating the text is valid
- if(numberOfCharacters > 0u &&
- (mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
- mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
- {
- std::string currentText;
- Utf32ToUtf8(mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
-
- DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
- DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
-
- // Dump mTextUpdateInfo
- DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
- DALI_LOG_ERROR(" mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove);
- DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd);
- DALI_LOG_ERROR(" mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters);
- DALI_LOG_ERROR(" mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters);
- DALI_LOG_ERROR(" mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines);
- DALI_LOG_ERROR(" mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll);
- DALI_LOG_ERROR(" mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded);
- DALI_LOG_ERROR(" mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph);
-
- return false;
- }
-
- startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
-
- if(mTextUpdateInfo.mClearAll ||
- (0u != paragraphCharacters))
- {
- ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
- }
-
- mTextUpdateInfo.mClearAll = false;
-
- // Whether the model is updated.
- bool updated = false;
-
- Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
- const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
-
- if(NO_OPERATION != (GET_LINE_BREAKS & operations))
- {
- // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
- // calculate the bidirectional info for each 'paragraph'.
- // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
- // is not shaped together).
- lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
-
- SetLineBreakInfo(utf32Characters,
- startIndex,
- requestedNumberOfCharacters,
- lineBreakInfo);
-
- // Create the paragraph info.
- mModel->mLogicalModel->CreateParagraphInfo(startIndex,
- requestedNumberOfCharacters);
- updated = true;
- }
-
- const bool getScripts = NO_OPERATION != (GET_SCRIPTS & operations);
- const bool validateFonts = NO_OPERATION != (VALIDATE_FONTS & operations);
-
- Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
- Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
-
- if(getScripts || validateFonts)
- {
- // Validates the fonts assigned by the application or assigns default ones.
- // It makes sure all the characters are going to be rendered by the correct font.
- MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
-
- if(getScripts)
- {
- // Retrieves the scripts used in the text.
- multilanguageSupport.SetScripts(utf32Characters,
- startIndex,
- requestedNumberOfCharacters,
- scripts);
- }
-
- if(validateFonts)
- {
- // Validate the fonts set through the mark-up string.
- Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
-
- // Get the default font's description.
- TextAbstraction::FontDescription defaultFontDescription;
- TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
-
- if(IsShowingPlaceholderText() && mEventData && (NULL != mEventData->mPlaceholderFont))
- {
- // If the placeholder font is set specifically, only placeholder font is changed.
- defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
- if(mEventData->mPlaceholderFont->sizeDefined)
- {
- defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * 64u;
- }
- }
- else if(NULL != mFontDefaults)
- {
- // Set the normal font and the placeholder font.
- defaultFontDescription = mFontDefaults->mFontDescription;
-
- if(mTextFitEnabled)
- {
- defaultPointSize = mFontDefaults->mFitPointSize * 64u;
- }
- else
- {
- defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * 64u;
- }
- }
-
- // Validates the fonts. If there is a character with no assigned font it sets a default one.
- // After this call, fonts are validated.
- multilanguageSupport.ValidateFonts(utf32Characters,
- scripts,
- fontDescriptionRuns,
- defaultFontDescription,
- defaultPointSize,
- startIndex,
- requestedNumberOfCharacters,
- validFonts);
- }
- updated = true;
- }
-
- Vector<Character> mirroredUtf32Characters;
- bool textMirrored = false;
- const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
- if(NO_OPERATION != (BIDI_INFO & operations))
- {
- Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
- bidirectionalInfo.Reserve(numberOfParagraphs);
-
- // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
- SetBidirectionalInfo(utf32Characters,
- scripts,
- lineBreakInfo,
- startIndex,
- requestedNumberOfCharacters,
- bidirectionalInfo,
- mModel->mMatchSystemLanguageDirection,
- mLayoutDirection);
-
- if(0u != bidirectionalInfo.Count())
- {
- // Only set the character directions if there is right to left characters.
- Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
- GetCharactersDirection(bidirectionalInfo,
- numberOfCharacters,
- startIndex,
- requestedNumberOfCharacters,
- directions);
-
- // This paragraph has right to left text. Some characters may need to be mirrored.
- // TODO: consider if the mirrored string can be stored as well.
-
- textMirrored = GetMirroredText(utf32Characters,
- directions,
- bidirectionalInfo,
- startIndex,
- requestedNumberOfCharacters,
- mirroredUtf32Characters);
- }
- else
- {
- // There is no right to left characters. Clear the directions vector.
- mModel->mLogicalModel->mCharacterDirections.Clear();
- }
- updated = true;
- }
-
- Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
- Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
- Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
- Vector<GlyphIndex> newParagraphGlyphs;
- newParagraphGlyphs.Reserve(numberOfParagraphs);
-
- const Length currentNumberOfGlyphs = glyphs.Count();
- if(NO_OPERATION != (SHAPE_TEXT & operations))
- {
- const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
- // Shapes the text.
- ShapeText(textToShape,
- lineBreakInfo,
- scripts,
- validFonts,
- startIndex,
- mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- glyphs,
- glyphsToCharactersMap,
- charactersPerGlyph,
- newParagraphGlyphs);
-
- // Create the 'number of glyphs' per character and the glyph to character conversion tables.
- mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
- mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
- updated = true;
- }
-
- const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
-
- if(NO_OPERATION != (GET_GLYPH_METRICS & operations))
- {
- GlyphInfo* glyphsBuffer = glyphs.Begin();
- mMetrics->GetGlyphMetrics(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
-
- // Update the width and advance of all new paragraph characters.
- for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
- {
- const GlyphIndex index = *it;
- GlyphInfo& glyph = *(glyphsBuffer + index);
-
- glyph.xBearing = 0.f;
- glyph.width = 0.f;
- glyph.advance = 0.f;
- }
- updated = true;
- }
-
- if((NULL != mEventData) &&
- mEventData->mPreEditFlag &&
- (0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
- {
- Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
- mEventData->mInputMethodContext.GetPreeditStyle(attrs);
- Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
-
- // Check the type of preedit and run it.
- for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
- {
- Dali::InputMethodContext::PreeditAttributeData attrData = *it;
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
- type = attrData.preeditType;
-
- // Check the number of commit characters for the start position.
- unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
- Length numberOfIndices = attrData.endIndex - attrData.startIndex;
-
- switch(type)
- {
- case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
- {
- // Add the underline for the pre-edit text.
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::REVERSE:
- {
- Vector4 textColor = mModel->mVisualModel->GetTextColor();
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = textColor;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
- Vector<ColorRun> colorRuns;
- colorRuns.Resize(1u);
- ColorRun& colorRun = *(colorRuns.Begin());
- colorRun.color = backgroundColor;
- colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- colorRun.characterRun.numberOfCharacters = numberOfIndices;
-
- mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
- {
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = LIGHT_BLUE;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
- {
- // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB4;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
- {
- // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB5;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
- {
- // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB6;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
- {
- // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB7;
- mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- GlyphRun underlineRun;
- underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.numberOfGlyphs = numberOfIndices;
- mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::NONE:
- default:
- {
- break;
- }
- }
- }
- attrs.Clear();
- updated = true;
- }
-
- if(NO_OPERATION != (COLOR & operations))
- {
- // Set the color runs in glyphs.
- SetColorSegmentationInfo(mModel->mLogicalModel->mColorRuns,
- mModel->mVisualModel->mCharactersToGlyph,
- mModel->mVisualModel->mGlyphsPerCharacter,
- startIndex,
- mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- mModel->mVisualModel->mColors,
- mModel->mVisualModel->mColorIndices);
-
- // Set the background color runs in glyphs.
- SetColorSegmentationInfo(mModel->mLogicalModel->mBackgroundColorRuns,
- mModel->mVisualModel->mCharactersToGlyph,
- mModel->mVisualModel->mGlyphsPerCharacter,
- startIndex,
- mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- mModel->mVisualModel->mBackgroundColors,
- mModel->mVisualModel->mBackgroundColorIndices);
-
- updated = true;
- }
-
- // The estimated number of lines. Used to avoid reallocations when layouting.
- mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
-
- // Set the previous number of characters for the next time the text is updated.
- mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
-
- return updated;
+ return ControllerImplModelUpdater::Update(*this, operationsRequired);
}
void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
{
- // Sets the default text's color.
- inputStyle.textColor = mTextColor;
- inputStyle.isDefaultColor = true;
-
- inputStyle.familyName.clear();
- inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
- inputStyle.width = TextAbstraction::FontWidth::NORMAL;
- inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
- inputStyle.size = 0.f;
-
- inputStyle.lineSpacing = 0.f;
-
- inputStyle.underlineProperties.clear();
- inputStyle.shadowProperties.clear();
- inputStyle.embossProperties.clear();
- inputStyle.outlineProperties.clear();
-
- inputStyle.isFamilyDefined = false;
- inputStyle.isWeightDefined = false;
- inputStyle.isWidthDefined = false;
- inputStyle.isSlantDefined = false;
- inputStyle.isSizeDefined = false;
-
- inputStyle.isLineSpacingDefined = false;
-
- inputStyle.isUnderlineDefined = false;
- inputStyle.isShadowDefined = false;
- inputStyle.isEmbossDefined = false;
- inputStyle.isOutlineDefined = false;
-
- // Sets the default font's family name, weight, width, slant and size.
- if(mFontDefaults)
- {
- if(mFontDefaults->familyDefined)
- {
- inputStyle.familyName = mFontDefaults->mFontDescription.family;
- inputStyle.isFamilyDefined = true;
- }
-
- if(mFontDefaults->weightDefined)
- {
- inputStyle.weight = mFontDefaults->mFontDescription.weight;
- inputStyle.isWeightDefined = true;
- }
-
- if(mFontDefaults->widthDefined)
- {
- inputStyle.width = mFontDefaults->mFontDescription.width;
- inputStyle.isWidthDefined = true;
- }
-
- if(mFontDefaults->slantDefined)
- {
- inputStyle.slant = mFontDefaults->mFontDescription.slant;
- inputStyle.isSlantDefined = true;
- }
-
- if(mFontDefaults->sizeDefined)
- {
- inputStyle.size = mFontDefaults->mDefaultPointSize;
- inputStyle.isSizeDefined = true;
- }
- }
+ SetDefaultInputStyle(inputStyle, mFontDefaults, mTextColor);
}
float Controller::Impl::GetDefaultFontLineHeight()
{
FontId defaultFontId = 0u;
- if(NULL == mFontDefaults)
+ if(nullptr == mFontDefaults)
{
TextAbstraction::FontDescription fontDescription;
defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
if(mEventData->mSelectionEnabled && (pStart || pEnd))
{
- uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+ uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+ uint32_t oldStart = mEventData->mLeftSelectionPosition;
+ uint32_t oldEnd = mEventData->mRightSelectionPosition;
if(pStart)
{
mEventData->mUpdateLeftSelectionPosition = true;
mEventData->mUpdateRightSelectionPosition = true;
}
+
+ if(mSelectableControlInterface != nullptr)
+ {
+ mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+ }
}
}
return mEventData->mPrimaryCursorPosition;
}
-bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index)
+bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
{
if(nullptr == mEventData)
{
return false;
}
- if(mEventData->mPrimaryCursorPosition == index)
+ if(mEventData->mPrimaryCursorPosition == index && mEventData->mState != EventData::SELECTING)
{
// Nothing for same cursor position.
return false;
}
uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+ uint32_t oldCursorPos = mEventData->mPrimaryCursorPosition;
mEventData->mPrimaryCursorPosition = std::min(index, length);
- ChangeState(EventData::EDITING);
- mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
- mEventData->mUpdateCursorPosition = true;
- ScrollTextToMatchCursor();
+ // If there is no focus, only the value is updated.
+ if(focused)
+ {
+ bool wasInSelectingState = mEventData->mState == EventData::SELECTING;
+ uint32_t oldStart = mEventData->mLeftSelectionPosition;
+ uint32_t oldEnd = mEventData->mRightSelectionPosition;
+ ChangeState(EventData::EDITING);
+ mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+ mEventData->mUpdateCursorPosition = true;
+
+ if(mSelectableControlInterface != nullptr && wasInSelectingState)
+ {
+ mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+ }
+
+ ScrollTextToMatchCursor();
+ }
+
+ if(nullptr != mEditableControlInterface)
+ {
+ mEditableControlInterface->CursorPositionChanged(oldCursorPos, mEventData->mPrimaryCursorPosition);
+ }
+
return true;
}
void Controller::Impl::SetSelection(int start, int end)
{
+ uint32_t oldStart = mEventData->mLeftSelectionPosition;
+ uint32_t oldEnd = mEventData->mRightSelectionPosition;
+
mEventData->mLeftSelectionPosition = start;
mEventData->mRightSelectionPosition = end;
mEventData->mUpdateCursorPosition = true;
+
+ if(mSelectableControlInterface != nullptr)
+ {
+ mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
+ }
}
std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
void Controller::Impl::ChangeState(EventData::State newState)
{
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
return;
cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
bool isRTL = false;
- if(mModel->mMatchSystemLanguageDirection)
+ if(mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS)
{
isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
}
CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
{
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
return 0u;
void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
void Controller::Impl::RequestRelayout()
{
- if(NULL != mControlInterface)
+ if(nullptr != mControlInterface)
{
mControlInterface->RequestTextRelayout();
}
Actor Controller::Impl::CreateBackgroundActor()
{
- // NOTE: Currently we only support background color for one line left-to-right text,
- // so the following calculation is based on one line left-to-right text only!
+ // NOTE: Currently we only support background color for left-to-right text.
Actor actor;
const Vector2 textSize = mView.GetLayoutSize();
- const float offsetX = textSize.width * 0.5f;
+ const float offsetX = alignmentOffset + textSize.width * 0.5f;
const float offsetY = textSize.height * 0.5f;
const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
- Vector4 quad;
- uint32_t numberOfQuads = 0u;
+ Vector4 quad;
+ uint32_t numberOfQuads = 0u;
+ Length yLineOffset = 0;
+ Length prevLineIndex = 0;
+ LineIndex lineIndex;
+ Length numberOfLines;
for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
{
// Get the background color of the character.
// The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
- const ColorIndex backgroundColorIndex = (nullptr == backgroundColorsBuffer) ? 0u : *(backgroundColorIndicesBuffer + i);
- const Vector4& backgroundColor = (0u == backgroundColorIndex) ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
+ const bool isMarkupBackground = mView.IsMarkupBackgroundColorSet();
+ const ColorIndex backgroundColorIndex = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
+ const bool isDefaultBackgroundColor = (0u == backgroundColorIndex);
+ const Vector4& backgroundColor = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
+
+ mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
+ Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
+
+ if(lineIndex != prevLineIndex)
+ {
+ yLineOffset += lineHeight;
+ }
// Only create quads for glyphs with a background color
if(backgroundColor != Color::TRANSPARENT)
if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
{
quad.x = position.x;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
- quad.w = textSize.height;
+ quad.w = lineHeight;
}
- else if(i == 0u) // The first glyph in the whole text
+ else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
{
quad.x = position.x;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x - glyph.xBearing + glyph.advance;
- quad.w = textSize.height;
+ quad.w = quad.y + lineHeight;
}
else if(i == glyphSize - 1u) // The last glyph in the whole text
{
quad.x = position.x - glyph.xBearing;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
- quad.w = textSize.height;
+ quad.w = quad.y + lineHeight;
}
else // The glyph in the middle of the text
{
quad.x = position.x - glyph.xBearing;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x + glyph.advance;
- quad.w = textSize.height;
+ quad.w = quad.y + lineHeight;
}
BackgroundVertex vertex;
numberOfQuads++;
}
+
+ if(lineIndex != prevLineIndex)
+ {
+ prevLineIndex = lineIndex;
+ }
}
// Only create the background actor if there are glyphs with background color
return actor;
}
-} // namespace Text
+void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
+{
+ //Underlined character runs for markup-processor
+ const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ if(shouldClearPreUnderlineRuns)
+ {
+ mModel->mVisualModel->mUnderlineRuns.Clear();
+ }
-} // namespace Toolkit
+ for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+ {
+ CharacterIndex characterIndex = it->characterRun.characterIndex;
+ Length numberOfCharacters = it->characterRun.numberOfCharacters;
+ for(Length index = 0u; index < numberOfCharacters; index++)
+ {
+ GlyphRun underlineGlyphRun;
+ underlineGlyphRun.glyphIndex = charactersToGlyph[characterIndex + index];
+ underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+ mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
+ }
+ }
+}
-} // namespace Dali
+} // namespace Dali::Toolkit::Text