/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/visual-model-impl.h>
using namespace Dali;
{
namespace Text
{
-bool GetNextLine(GlyphIndex index, LineIndex& lineIndex, LineRun*& lineRun, GlyphIndex& lastGlyphOfLine, Length numberOfLines)
+bool GetNextLine(GlyphIndex index, LineIndex& lineIndex, LineRun*& lineRun, GlyphIndex& lastGlyphOfLine, Length numberOfLines, bool& isLastLine)
{
if(index == lastGlyphOfLine)
{
++lineIndex;
if(lineIndex < numberOfLines)
{
+ isLastLine = (lineIndex + 1 == numberOfLines);
++lineRun;
return true;
}
return false;
}
-void UpdateLineInfo(const LineRun* lineRun, float& currentLineOffset, float& currentLineHeight, GlyphIndex& lastGlyphOfLine)
+void UpdateLineInfo(const LineRun* lineRun, float& currentLineOffset, float& currentLineHeight, GlyphIndex& lastGlyphOfLine, bool isLastLine)
{
lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
currentLineOffset = currentLineOffset + currentLineHeight;
- currentLineHeight = GetLineHeight(*lineRun);
+ currentLineHeight = GetLineHeight(*lineRun, isLastLine);
}
void GetTextGeometry(ModelPtr textModel, CharacterIndex startIndex, CharacterIndex endIndex, Vector<Vector2>& sizesList, Vector<Vector2>& positionsList)
const CharacterIndex* const glyphToCharacterBuffer = visualModel->mGlyphsToCharacters.Begin();
const CharacterDirection* const modelCharacterDirectionsBuffer = (0u != logicalModel->mCharacterDirections.Count()) ? logicalModel->mCharacterDirections.Begin() : NULL;
+ //Clear the lists
+ sizesList.Clear();
+ positionsList.Clear();
+
+ if(charactersToGlyphBuffer == nullptr || glyphsPerCharacterBuffer == nullptr || charactersPerGlyphBuffer == nullptr || glyphToCharacterBuffer == nullptr )
+ {
+ return;
+ }
+
if(startIndex >= logicalModel->mText.Count() && endIndex >= logicalModel->mText.Count())
+ {
return;
+ }
if(startIndex >= logicalModel->mText.Count())
- startIndex = logicalModel->mText.Count() - 1;
+ {
+ startIndex = static_cast<CharacterIndex>(logicalModel->mText.Count() - 1u);
+ }
if(endIndex >= logicalModel->mText.Count())
- endIndex = logicalModel->mText.Count() - 1;
+ {
+ endIndex = static_cast<CharacterIndex>(logicalModel->mText.Count() - 1u);
+ }
if(startIndex > endIndex)
{
GlyphIndex glyphEnd = *(charactersToGlyphBuffer + endIndex) + ((numberOfGlyphs > 0) ? numberOfGlyphs - 1u : 0u);
LineIndex lineIndex = visualModel->GetLineOfCharacter(startIndex);
Length numberOfLines = visualModel->GetTotalNumberOfLines();
+ bool isLastLine = lineIndex + 1 == numberOfLines;
LineIndex firstLineIndex = lineIndex;
Size textInLineSize;
//get the first line and its vertical offset
float currentLineOffset = CalculateLineOffset(visualModel->mLines, firstLineIndex);
- float currentLineHeight = GetLineHeight(*lineRun);
+ float currentLineHeight = GetLineHeight(*lineRun, isLastLine);
GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1;
// Check if the first/last glyph is a ligature that needs be splitted like English fi or Arabic ﻻ.
positionsList.PushBack(blockPos);
}
- if(GetNextLine(index, lineIndex, lineRun, lastGlyphOfLine, numberOfLines))
+ if(GetNextLine(index, lineIndex, lineRun, lastGlyphOfLine, numberOfLines, isLastLine))
{
- UpdateLineInfo(lineRun, currentLineOffset, currentLineHeight, lastGlyphOfLine);
+ UpdateLineInfo(lineRun, currentLineOffset, currentLineHeight, lastGlyphOfLine, isLastLine);
}
// Ignore any glyph that was removed
continue;
}
else
{
- if((ellipsisPosition == DevelText::EllipsisPosition::END) && (index >= endIndexOfGlyphs))
+ if((ellipsisPosition == DevelText::EllipsisPosition::END) && (index > endIndexOfGlyphs))
{
//skip remaining elided glyphs
break;
}
else if((ellipsisPosition == DevelText::EllipsisPosition::START) && (index <= startIndexOfGlyphs))
{
- if(GetNextLine(index, lineIndex, lineRun, lastGlyphOfLine, numberOfLines))
+ if(GetNextLine(index, lineIndex, lineRun, lastGlyphOfLine, numberOfLines, isLastLine))
{
- UpdateLineInfo(lineRun, currentLineOffset, currentLineHeight, lastGlyphOfLine);
+ UpdateLineInfo(lineRun, currentLineOffset, currentLineHeight, lastGlyphOfLine, isLastLine);
}
continue;
currentSize.y = currentLineHeight;
// if there is next line to retrieve.
- if(GetNextLine(index, lineIndex, lineRun, lastGlyphOfLine, numberOfLines))
+ if(GetNextLine(index, lineIndex, lineRun, lastGlyphOfLine, numberOfLines, isLastLine))
{
- UpdateLineInfo(lineRun, currentLineOffset, currentLineHeight, lastGlyphOfLine);
+ UpdateLineInfo(lineRun, currentLineOffset, currentLineHeight, lastGlyphOfLine, isLastLine);
}
}
positionsList.PushBack(blockPos);
}
+float GetLineLeft(const LineRun& lineRun)
+{
+ return lineRun.alignmentOffset;
+}
+
+float GetLineTop(const Vector<LineRun>& lines, const LineRun& lineRun)
+{
+ float lineTop = 0;
+ const int numberOfLines = (int)lines.Count();
+
+ int currentLineIndex = 0;
+ Vector<LineRun>::ConstIterator endIt = (&lineRun);
+ for(Vector<LineRun>::Iterator it = lines.Begin();
+ it != endIt;
+ ++it, ++currentLineIndex)
+ {
+ LineRun& line = *it;
+ bool isLastLine = (currentLineIndex + 1) == numberOfLines;
+ lineTop += GetLineHeight(line, isLastLine);
+ }
+
+ return lineTop;
+}
+
+float GetLineWidth(const LineRun& lineRun)
+{
+ return lineRun.width;
+}
+
+Rect<float> GetLineBoundingRect(ModelPtr textModel, const uint32_t lineIndex)
+{
+
+ if(textModel->mVisualModel == nullptr)
+ {
+ return {0, 0, 0, 0};
+ }
+
+ Length numberOfLines = textModel->mVisualModel->GetTotalNumberOfLines();
+
+ if(lineIndex >= numberOfLines)
+ {
+ return {0, 0, 0, 0};
+ }
+
+ const Vector<LineRun>& lines = textModel->mVisualModel->mLines;
+ const LineRun& lineRun = lines[lineIndex];
+ bool isFirstLine = lineIndex == 0;
+ bool isLastLine = (lineIndex + 1) == numberOfLines;
+
+ // Calculate the Left(lineX) = X position.
+ float lineX = GetLineLeft(lineRun) + textModel->mScrollPosition.x;
+
+ // Calculate the Top(lineY) = PreviousHeights.
+ // If the line is the first line of the text; its top = 0.
+ float lineY = (isFirstLine ? 0 : GetLineTop(lines, lineRun)) + textModel->mScrollPosition.y;
+
+ // The rectangle contains the width and height:
+ float lineWidth = GetLineWidth(lineRun);
+ float lineHeight = GetLineHeight(lineRun, isLastLine);
+
+ return {lineX, lineY, lineWidth, lineHeight};
+}
+
+float GetCharacterLeft(const GlyphInfo& glyph, const Vector2& characterPosition)
+{
+ return characterPosition.x - glyph.xBearing;
+}
+
+float GetCharacterTop(const float& yPosition)
+{
+ return (-1 * yPosition);
+}
+
+float GetCharacterHeight(const GlyphInfo& glyph)
+{
+ return glyph.height;
+}
+
+float GetCharacterWidth(const GlyphInfo& glyph)
+{
+ return glyph.advance;
+}
+
+Rect<> GetCharacterBoundingRect(ModelPtr textModel, const uint32_t charIndex)
+{
+ if(textModel->mVisualModel == nullptr)
+ {
+ return {0, 0, 0, 0};
+ }
+
+ VisualModelPtr& visualModel = textModel->mVisualModel;
+ LogicalModelPtr& logicalModel = textModel->mLogicalModel;
+
+ if(charIndex >= logicalModel->mText.Count() || visualModel->mLines.Empty())
+ {
+ return {0, 0, 0, 0};
+ }
+
+ const Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
+ const Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
+ const Vector<LineRun>& lines = visualModel->mLines;
+
+ //For each character, the index of the first glyph.
+ const GlyphIndex glyphIndex = visualModel->mCharactersToGlyph[charIndex]; //took its glyphs
+
+ const Vector2& characterPosition = glyphPositions[glyphIndex];
+ const GlyphInfo& glyphInfo = glyphs[glyphIndex];
+
+ // GetLineOfCharacter function returns 0 if the lines are empty
+ const int lineIndex = visualModel->GetLineOfCharacter(charIndex);
+ const LineRun& lineRun = lines[lineIndex];
+
+ //Calculate the left: x position of the glyph + alignmentOffset of the line + mScrollPosition.x.
+ float characterX = lineRun.alignmentOffset + GetCharacterLeft(glyphInfo, characterPosition) + textModel->mScrollPosition.x;
+
+ //Calculate the Top(characterY): position.Y + previouse lines height + mScrollPosition.y.
+ bool isFirstLine = lineIndex == 0;
+
+ //If the line is the first line of the text; its top = 0.
+ float lineY = (isFirstLine ? 0 : GetLineTop(lines, lineRun));
+
+ float characterY = lineY + GetCharacterTop(characterPosition.y) + textModel->mScrollPosition.y;
+
+ //The rectangle contains the width and height:
+ float characterWidth = GetCharacterWidth(glyphInfo);
+ float characterHeight = GetCharacterHeight(glyphInfo);
+
+ return {characterX, characterY, characterWidth, characterHeight};
+}
+
} // namespace Text
} // namespace Toolkit