${toolkit_src_dir}/text/bidirectional-support.cpp
${toolkit_src_dir}/text/bounded-paragraph-helper-functions.cpp
${toolkit_src_dir}/text/character-set-conversion.cpp
+ ${toolkit_src_dir}/text/characters-helper-functions.cpp
${toolkit_src_dir}/text/color-segmentation.cpp
${toolkit_src_dir}/text/cursor-helper-functions.cpp
${toolkit_src_dir}/text/glyph-metrics-helper.cpp
${toolkit_src_dir}/text/markup-processor-span.cpp
${toolkit_src_dir}/text/markup-processor-strikethrough.cpp
${toolkit_src_dir}/text/markup-processor-underline.cpp
+ ${toolkit_src_dir}/text/markup-processor-character-spacing.cpp
${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
${toolkit_src_dir}/text/markup-processor-attribute-helper-functions.cpp
${toolkit_src_dir}/text/multi-language-support.cpp
${toolkit_src_dir}/text/rendering/text-typesetter.cpp
${toolkit_src_dir}/text/rendering/view-model.cpp
${toolkit_src_dir}/text/rendering/styles/underline-helper-functions.cpp
- ${toolkit_src_dir}/text/rendering/styles/strikethrough-helper-functions
+ ${toolkit_src_dir}/text/rendering/styles/strikethrough-helper-functions.cpp
+ ${toolkit_src_dir}/text/rendering/styles/character-spacing-helper-functions.cpp
${toolkit_src_dir}/transition/fade-transition-impl.cpp
${toolkit_src_dir}/transition/slide-transition-impl.cpp
${toolkit_src_dir}/transition/scale-transition-impl.cpp
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
+ #include <dali-toolkit/internal/text/characters-helper-functions.h>
+ #include <dali-toolkit/internal/text/emoji-helper.h>
#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
namespace
{
{
return logicalIndex;
}
- const float characterSpacing = visualModel->GetCharacterSpacing();
+
+ // Get the character-spacing runs.
+ const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
+ const float modelCharacterSpacing = visualModel->GetCharacterSpacing();
// Whether there is a hit on a line.
bool matchedLine = false;
// Get the metrics for the group of glyphs.
GlyphMetrics glyphMetrics;
- calculatedAdvance = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + firstLogicalGlyphIndex))), characterSpacing, (*(visualModel->mGlyphs.Begin() + firstLogicalGlyphIndex)).advance);
+ const float characterSpacing = GetGlyphCharacterSpacing(firstLogicalGlyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+ calculatedAdvance = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + firstLogicalGlyphIndex))), characterSpacing, (*(visualModel->mGlyphs.Begin() + firstLogicalGlyphIndex)).advance);
GetGlyphsMetrics(firstLogicalGlyphIndex,
numberOfGlyphs,
glyphMetrics,
logicalIndex = (bidiLineFetched ? logicalModel->GetLogicalCursorIndex(visualIndex) : visualIndex);
+ // Handle Emoji clustering for cursor handling:
+ // Fixing this case:
+ // - When there is Emoji contains multi unicodes and it is layoutted at the end of line (LineWrap case , is not new line case)
+ // - Try to click at the center or at the end of Emoji then the cursor appears inside Emoji
+ // - Example:"FamilyManWomanGirlBoy 👨‍👩‍👧‍👦"
+ const Script script = logicalModel->GetScript(logicalIndex);
+ if(IsOneOfEmojiScripts(script))
+ {
+ //TODO: Use this clustering for Emoji cases only. This needs more testing to generalize to all scripts.
+ CharacterRun emojiClusteredCharacters = RetrieveClusteredCharactersOfCharacterIndex(visualModel, logicalModel, logicalIndex);
+ logicalIndex = emojiClusteredCharacters.characterIndex;
+ }
+
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "closest visualIndex %d logicalIndex %d\n", visualIndex, logicalIndex);
DALI_ASSERT_DEBUG((logicalIndex <= logicalModel->mText.Count() && logicalIndex >= 0) && "GetClosestCursorIndex - Out of bounds index");
const Length* const charactersPerGlyphBuffer = parameters.visualModel->mCharactersPerGlyph.Begin();
const CharacterIndex* const glyphsToCharactersBuffer = parameters.visualModel->mGlyphsToCharacters.Begin();
const Vector2* const glyphPositionsBuffer = parameters.visualModel->mGlyphPositions.Begin();
- const float characterSpacing = parameters.visualModel->GetCharacterSpacing();
+ const float modelCharacterSpacing = parameters.visualModel->GetCharacterSpacing();
+
+ const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = parameters.visualModel->GetCharacterSpacingGlyphRuns();
// Get the metrics for the group of glyphs.
GetGlyphMetricsFromCharacterIndex(index, parameters.visualModel, parameters.logicalModel, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
const bool addGlyphAdvance = ((!isFirstPositionOfLine && !isCurrentRightToLeft) ||
(isFirstPositionOfLine && !isRightToLeftParagraph));
+ const float characterSpacing = GetGlyphCharacterSpacing(secondaryGlyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + secondaryPosition.x + (addGlyphAdvance ? (glyphMetrics.advance + characterSpacing) : 0.f);
cursorInfo.secondaryPosition.y = cursorInfo.lineOffset + cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight;
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/character-set-conversion.h>
+ #include <dali-toolkit/internal/text/characters-helper-functions.h>
+ #include <dali-toolkit/internal/text/emoji-helper.h>
#include <dali-toolkit/internal/text/markup-processor.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
#include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
logicalModel->mUnderlinedCharacterRuns,
logicalModel->mBackgroundColorRuns,
logicalModel->mStrikethroughCharacterRuns,
- logicalModel->mBoundedParagraphRuns);
+ logicalModel->mBoundedParagraphRuns,
+ logicalModel->mCharacterSpacingCharacterRuns);
Length textSize = 0u;
const uint8_t* utf8 = NULL;
ModelPtr& model = impl.mModel;
LogicalModelPtr& logicalModel = model->mLogicalModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n", &controller, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters);
cursorIndex = eventData->mPrimaryCursorPosition + cursorOffset;
}
+ //Handle Emoji clustering for cursor handling
+ // Deletion case: this is handling the deletion cases when the cursor is before or after Emoji
+ // - Before: when use delete key and cursor is before Emoji (cursorOffset = -1)
+ // - After: when use backspace key and cursor is after Emoji (cursorOffset = 0)
+
+ const Script script = logicalModel->GetScript(cursorIndex);
+ if((numberOfCharacters == 1u) &&
+ (IsOneOfEmojiScripts(script)))
+ {
+ //TODO: Use this clustering for Emoji cases only. This needs more testing to generalize to all scripts.
+ CharacterRun emojiClusteredCharacters = RetrieveClusteredCharactersOfCharacterIndex(visualModel, logicalModel, cursorIndex);
+ Length actualNumberOfCharacters = emojiClusteredCharacters.numberOfCharacters;
+
+ //Set cursorIndex at the first characterIndex of clustred Emoji
+ cursorIndex = emojiClusteredCharacters.characterIndex;
+
+ numberOfCharacters = actualNumberOfCharacters;
+ }
+
if((cursorIndex + numberOfCharacters) > currentText.Count())
{
numberOfCharacters = currentText.Count() - cursorIndex;