+ /**
+ * 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;
+
+ if( isLastLine && !layoutParameters.isLastNewParagraph )
+ {
+ lineRun.width = layout.length;
+ if( LTR == layout.direction )
+ {
+ lineRun.width += layout.whiteSpaceLengthEndOfLine;
+ lineRun.extraLength = 0.f;
+ }
+ else
+ {
+ lineRun.extraLength = layout.whiteSpaceLengthEndOfLine;
+ }
+ }
+ else
+ {
+ 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;
+ }
+ }
+
+ bool LayoutText( Parameters& layoutParameters,
+ Size& layoutSize,
+ bool elideTextEnabled,
+ bool& isAutoScrollEnabled )