+
+ ++characterLogicalIndex;
+ characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+ }
+
+ const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+ const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+
+ penX += -glyph.xBearing;
+
+ // Traverses the characters of the right to left paragraph.
+ for( ; characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
+ ++characterLogicalIndex )
+ {
+ // Convert the character in the logical order into the character in the visual order.
+ const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+
+ // Get the number of glyphs of the character.
+ const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterVisualIndex );
+
+ for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
+ {
+ // Convert the character in the visual order into the glyph in the visual order.
+ const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex ) + index;
+
+ DALI_ASSERT_DEBUG( glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count() );
+
+ const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+ Vector2& position = *( glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex );
+
+ position.x = std::round( penX + glyph.xBearing );
+ position.y = -glyph.yBearing;
+
+ penX += ( glyph.advance + layoutParameters.interGlyphExtraAdvance );
+ }
+ }
+ }
+
+ /**
+ * @brief Resizes the line buffer.
+ *
+ * @param[in,out] lines The vector of lines. Used when the layout is created from scratch.
+ * @param[in,out] newLines The vector of lines used instead of @p lines when the layout is updated.
+ * @param[in,out] linesCapacity The capacity of the vector (either lines or newLines).
+ * @param[in] updateCurrentBuffer Whether the layout is updated.
+ *
+ * @return Pointer to either lines or newLines.
+ */
+ LineRun* ResizeLinesBuffer( Vector<LineRun>& lines,
+ Vector<LineRun>& newLines,
+ Length& linesCapacity,
+ bool updateCurrentBuffer )
+ {
+ LineRun* linesBuffer = nullptr;
+ // Reserve more space for the next lines.
+ linesCapacity *= 2u;
+ if( updateCurrentBuffer )
+ {
+ newLines.Resize( linesCapacity );
+ linesBuffer = newLines.Begin();
+ }
+ else
+ {
+ lines.Resize( linesCapacity );
+ linesBuffer = lines.Begin();
+ }
+
+ return linesBuffer;
+ }
+
+ /**
+ * Ellipsis a line if it exceeds the width's of the bounding box.
+ *
+ * @param[in] layoutParameters The parameters needed to layout the text.
+ * @param[in] layout The line layout.
+ * @param[in,out] layoutSize The text's layout size.
+ * @param[in,out] linesBuffer Pointer to the line's buffer.
+ * @param[in,out] glyphPositionsBuffer Pointer to the position's buffer.
+ * @param[in,out] numberOfLines The number of laid-out lines.
+ * @param[in] penY The vertical layout position.
+ * @param[in] currentParagraphDirection The current paragraph's direction.
+ * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
+ *
+ * return Whether the line is ellipsized.
+ */
+ bool EllipsisLine( const Parameters& layoutParameters,
+ LayoutBidiParameters& layoutBidiParameters,
+ const LineLayout& layout,
+ Size& layoutSize,
+ LineRun* linesBuffer,
+ Vector2* glyphPositionsBuffer,
+ Length& numberOfLines,
+ float penY,
+ bool& isAutoScrollEnabled )
+ {
+ const bool ellipsis = isAutoScrollEnabled ? ( penY - layout.descender > layoutParameters.boundingBox.height ) :
+ ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
+ ( ( mLayout == SINGLE_LINE_BOX ) &&
+ ( layout.length > layoutParameters.boundingBox.width ) ) );
+
+ if( ellipsis )
+ {
+ isAutoScrollEnabled = false;
+ // Do not layout more lines if ellipsis is enabled.
+
+ // The last line needs to be completely filled with characters.
+ // Part of a word may be used.
+
+ LineRun* lineRun = nullptr;
+ LineLayout ellipsisLayout;
+ if( 0u != numberOfLines )
+ {
+ // Get the last line and layout it again with the 'completelyFill' flag to true.
+ lineRun = linesBuffer + ( numberOfLines - 1u );
+
+ penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
+
+ ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
+ }
+ else
+ {
+ // At least there is space reserved for one line.
+ lineRun = linesBuffer;
+
+ lineRun->glyphRun.glyphIndex = 0u;
+ ellipsisLayout.glyphIndex = 0u;
+
+ ++numberOfLines;
+ }
+
+ GetLineLayoutForBox( layoutParameters,
+ layoutBidiParameters,
+ ellipsisLayout,
+ true );
+
+ lineRun->glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
+ lineRun->characterRun.characterIndex = ellipsisLayout.characterIndex;
+ lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
+ lineRun->width = ellipsisLayout.length;
+ lineRun->extraLength = std::ceil( ellipsisLayout.whiteSpaceLengthEndOfLine );
+ lineRun->ascender = ellipsisLayout.ascender;
+ lineRun->descender = ellipsisLayout.descender;
+ lineRun->ellipsis = true;
+
+ layoutSize.width = layoutParameters.boundingBox.width;
+ if( layoutSize.height < Math::MACHINE_EPSILON_1000 )
+ {
+ layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
+ }
+
+ const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+ const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
+ const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+ if( layoutBidiParameters.isBidirectional )
+ {
+ layoutBidiParameters.bidiLineIndex = 0u;
+ for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLinesInfo.Begin(),
+ endIt = bidirectionalLinesInfo.End();
+ it != endIt;
+ ++it, ++layoutBidiParameters.bidiLineIndex )
+ {
+ const BidirectionalLineInfoRun& run = *it;
+
+ if( ellipsisLayout.characterIndex == run.characterRun.characterIndex )
+ {
+ // Found where to insert the bidi line info.
+ break;
+ }
+ }
+ }
+
+ const BidirectionalLineInfoRun* const bidirectionalLineInfo = ( layoutBidiParameters.isBidirectional && !bidirectionalLinesInfo.Empty() ) ? &bidirectionalLinesInfo[layoutBidiParameters.bidiLineIndex] : nullptr;
+
+ if( ( nullptr != bidirectionalLineInfo ) &&
+ !bidirectionalLineInfo->isIdentity &&
+ ( ellipsisLayout.characterIndex == bidirectionalLineInfo->characterRun.characterIndex ) )
+ {
+ lineRun->direction = RTL;
+ SetGlyphPositions( layoutParameters,
+ glyphPositionsBuffer,
+ layoutBidiParameters,
+ ellipsisLayout );
+ }
+ else
+ {
+ lineRun->direction = LTR;
+ SetGlyphPositions( glyphsBuffer + lineRun->glyphRun.glyphIndex,
+ ellipsisLayout.numberOfGlyphs,
+ outlineWidth,
+ layoutParameters.interGlyphExtraAdvance,
+ glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
+ }
+ }
+
+ return ellipsis;
+ }
+
+ /**
+ * @brief Updates the text layout with a new laid-out line.
+ *
+ * @param[in] layoutParameters The parameters needed to layout the text.
+ * @param[in] layout The line layout.
+ * @param[in,out] layoutSize The text's layout size.
+ * @param[in,out] linesBuffer Pointer to the line's buffer.
+ * @param[in] index Index to the vector of glyphs.
+ * @param[in,out] numberOfLines The number of laid-out lines.
+ * @param[in] isLastLine Whether the laid-out line is the last one.
+ */
+ void UpdateTextLayout( const Parameters& layoutParameters,
+ const LineLayout& layout,
+ Size& layoutSize,
+ LineRun* linesBuffer,
+ GlyphIndex index,
+ Length& numberOfLines,
+ bool isLastLine )
+ {
+ LineRun& lineRun = *( linesBuffer + numberOfLines );
+ ++numberOfLines;
+
+ lineRun.glyphRun.glyphIndex = index;
+ lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
+ lineRun.characterRun.characterIndex = layout.characterIndex;
+ lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
+ lineRun.lineSpacing = mDefaultLineSpacing;
+
+ lineRun.width = layout.length;
+ lineRun.extraLength = std::ceil( layout.whiteSpaceLengthEndOfLine );
+
+
+ // Rounds upward to avoid a non integer size.
+ lineRun.width = std::ceil( lineRun.width );
+
+ lineRun.ascender = layout.ascender;
+ lineRun.descender = layout.descender;
+ lineRun.direction = layout.direction;
+ lineRun.ellipsis = false;
+
+ // Update the actual size.
+ if( lineRun.width > layoutSize.width )
+ {
+ layoutSize.width = lineRun.width;
+ }
+
+ layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
+ }
+
+ /**
+ * @brief Updates the text layout with the last laid-out line.
+ *
+ * @param[in] layoutParameters The parameters needed to layout the text.
+ * @param[in] characterIndex The character index of the line.
+ * @param[in] glyphIndex The glyph index of the line.
+ * @param[in,out] layoutSize The text's layout size.
+ * @param[in,out] linesBuffer Pointer to the line's buffer.
+ * @param[in,out] numberOfLines The number of laid-out lines.
+ */
+ void UpdateTextLayout( const Parameters& layoutParameters,
+ CharacterIndex characterIndex,
+ GlyphIndex glyphIndex,
+ Size& layoutSize,
+ LineRun* linesBuffer,
+ Length& numberOfLines )
+ {
+ const Vector<GlyphInfo>& glyphs = layoutParameters.textModel->mVisualModel->mGlyphs;
+
+ // Need to add a new line with no characters but with height to increase the layoutSize.height
+ const GlyphInfo& glyphInfo = glyphs[glyphs.Count() - 1u];
+
+ Text::FontMetrics fontMetrics;
+ if( 0u != glyphInfo.fontId )
+ {
+ mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
+ }
+
+ LineRun& lineRun = *( linesBuffer + numberOfLines );
+ ++numberOfLines;
+
+ lineRun.glyphRun.glyphIndex = glyphIndex;
+ lineRun.glyphRun.numberOfGlyphs = 0u;
+ lineRun.characterRun.characterIndex = characterIndex;
+ lineRun.characterRun.numberOfCharacters = 0u;
+ lineRun.width = 0.f;
+ lineRun.ascender = fontMetrics.ascender;
+ lineRun.descender = fontMetrics.descender;
+ lineRun.extraLength = 0.f;
+ lineRun.alignmentOffset = 0.f;
+ lineRun.direction = LTR;
+ lineRun.ellipsis = false;
+ lineRun.lineSpacing = mDefaultLineSpacing;
+
+ layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
+ }
+
+ /**
+ * @brief Updates the text's layout size adding the size of the previously laid-out lines.
+ *
+ * @param[in] lines The vector of lines (before the new laid-out lines are inserted).
+ * @param[in,out] layoutSize The text's layout size.
+ */
+ void UpdateLayoutSize( const Vector<LineRun>& lines,
+ Size& layoutSize )
+ {
+ for( Vector<LineRun>::ConstIterator it = lines.Begin(),
+ endIt = lines.End();
+ it != endIt;
+ ++it )
+ {
+ const LineRun& line = *it;
+
+ if( line.width > layoutSize.width )
+ {
+ layoutSize.width = line.width;
+ }
+
+ layoutSize.height += ( line.ascender + -line.descender ) + line.lineSpacing;
+ }
+ }
+
+ /**
+ * @brief Updates the indices of the character and glyph runs of the lines before the new lines are inserted.
+ *
+ * @param[in] layoutParameters The parameters needed to layout the text.
+ * @param[in,out] lines The vector of lines (before the new laid-out lines are inserted).
+ * @param[in] characterOffset The offset to be added to the runs of characters.
+ * @param[in] glyphOffset The offset to be added to the runs of glyphs.
+ */
+ void UpdateLineIndexOffsets( const Parameters& layoutParameters,
+ Vector<LineRun>& lines,
+ Length characterOffset,
+ Length glyphOffset )
+ {
+ // Update the glyph and character runs.
+ for( Vector<LineRun>::Iterator it = lines.Begin() + layoutParameters.startLineIndex,
+ endIt = lines.End();
+ it != endIt;
+ ++it )
+ {
+ LineRun& line = *it;
+
+ line.glyphRun.glyphIndex = glyphOffset;
+ line.characterRun.characterIndex = characterOffset;
+
+ glyphOffset += line.glyphRun.numberOfGlyphs;
+ characterOffset += line.characterRun.numberOfCharacters;