+
+ ++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 );
+ }