+ void LayoutRightToLeft( const Parameters& parameters,
+ const BidirectionalLineInfoRun& bidirectionalLineInfo,
+ float& length,
+ float& whiteSpaceLengthEndOfLine )
+ {
+ const Character* const textBuffer = parameters.textModel->mLogicalModel->mText.Begin();
+ const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+ const GlyphInfo* const glyphsBuffer = parameters.textModel->mVisualModel->mGlyphs.Begin();
+ const GlyphIndex* const charactersToGlyphsBuffer = parameters.textModel->mVisualModel->mCharactersToGlyph.Begin();
+
+ const float outlineWidth = static_cast<float>( parameters.textModel->GetOutlineWidth() );
+ const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+
+ CharacterIndex characterLogicalIndex = 0u;
+ CharacterIndex characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+
+ if( RTL == bidirectionalLineInfo.direction )
+ {
+ while( TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) ) )
+ {
+ const GlyphInfo& glyphInfo = *( glyphsBuffer + *( charactersToGlyphsBuffer + characterVisualIndex ) );
+
+ whiteSpaceLengthEndOfLine += glyphInfo.advance;
+
+ ++characterLogicalIndex;
+ characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+ }
+ }
+
+ const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+
+ // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
+ const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+ lastGlyphOfParagraphPlusOne,
+ charactersPerGlyphBuffer );
+
+ GlyphMetrics glyphMetrics;
+ GetGlyphsMetrics( glyphIndex,
+ numberOfGLyphsInGroup,
+ glyphMetrics,
+ glyphsBuffer,
+ mMetrics );
+
+ float penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
+
+ // Traverses the characters of the right to left paragraph.
+ for( ; characterLogicalIndex < bidirectionalLineInfo.characterRun.numberOfCharacters; )
+ {
+ // Convert the character in the logical order into the character in the visual order.
+ const CharacterIndex characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+ const bool isWhiteSpace = TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) );
+
+ const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+
+ // Check whether this glyph comes from a character that is shaped in multiple glyphs.
+ const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+ lastGlyphOfParagraphPlusOne,
+ charactersPerGlyphBuffer );
+
+ characterLogicalIndex += *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+
+ GlyphMetrics glyphMetrics;
+ GetGlyphsMetrics( glyphIndex,
+ numberOfGLyphsInGroup,
+ glyphMetrics,
+ glyphsBuffer,
+ mMetrics );
+
+ if( isWhiteSpace )
+ {
+ if( RTL == bidirectionalLineInfo.direction )
+ {
+ length += glyphMetrics.advance;
+ }
+ else
+ {
+ whiteSpaceLengthEndOfLine += glyphMetrics.advance;
+ }
+ penX += glyphMetrics.advance;
+ }
+ else
+ {
+ if( LTR == bidirectionalLineInfo.direction )
+ {
+ whiteSpaceLengthEndOfLine = 0.f;
+ }
+ length = std::max( length, penX + glyphMetrics.xBearing + glyphMetrics.width );
+ penX += ( glyphMetrics.advance + parameters.interGlyphExtraAdvance );
+ }
+ }
+ }
+
+ void ReorderBiDiLayout( const Parameters& parameters,
+ LayoutBidiParameters& bidiParameters,
+ const LineLayout& currentLineLayout,
+ LineLayout& lineLayout,
+ bool breakInCharacters )
+ {
+ const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+
+ // The last glyph to be laid-out.
+ const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+
+ const Vector<BidirectionalParagraphInfoRun>& bidirectionalParagraphsInfo = parameters.textModel->mLogicalModel->mBidirectionalParagraphInfo;
+
+ const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo = bidirectionalParagraphsInfo[bidiParameters.bidiParagraphIndex];
+ if( ( lineLayout.characterIndex >= bidirectionalParagraphInfo.characterRun.characterIndex ) &&
+ ( lineLayout.characterIndex < bidirectionalParagraphInfo.characterRun.characterIndex + bidirectionalParagraphInfo.characterRun.numberOfCharacters ) )
+ {
+ Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = parameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+ // Sets the visual to logical map tables needed to reorder the text.
+ ReorderLine( bidirectionalParagraphInfo,
+ bidirectionalLinesInfo,
+ bidiParameters.bidiLineIndex,
+ lineLayout.characterIndex,
+ lineLayout.numberOfCharacters,
+ bidiParameters.paragraphDirection );
+
+ // Recalculate the length of the line and update the layout.
+ const BidirectionalLineInfoRun& bidirectionalLineInfo = *( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+ if( !bidirectionalLineInfo.isIdentity )
+ {
+ float length = 0.f;
+ float whiteSpaceLengthEndOfLine = 0.f;
+ LayoutRightToLeft( parameters,
+ bidirectionalLineInfo,
+ length,
+ whiteSpaceLengthEndOfLine );
+
+ lineLayout.whiteSpaceLengthEndOfLine = whiteSpaceLengthEndOfLine;
+ if( !Equals( length, lineLayout.length ) )
+ {
+ const bool isMultiline = mLayout == MULTI_LINE_BOX;
+
+ if( isMultiline && ( length > parameters.boundingBox.width ) )
+ {
+ if( breakInCharacters || ( isMultiline && ( 0u == currentLineLayout.numberOfGlyphs ) ) )
+ {
+ // The word doesn't fit in one line. It has to be split by character.
+
+ // Remove the last laid out glyph(s) as they doesn't fit.
+ for( GlyphIndex glyphIndex = lineLayout.glyphIndex + lineLayout.numberOfGlyphs - 1u; glyphIndex >= lineLayout.glyphIndex; )
+ {
+ const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+ lastGlyphOfParagraphPlusOne,
+ charactersPerGlyphBuffer );
+
+ const Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+
+ lineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+ lineLayout.numberOfCharacters -= numberOfCharacters;
+
+ AdjustLayout( parameters,
+ bidiParameters,
+ bidirectionalParagraphInfo,
+ lineLayout );
+
+ if( lineLayout.length < parameters.boundingBox.width )
+ {
+ break;
+ }
+
+ if( glyphIndex < numberOfGLyphsInGroup )
+ {
+ // avoids go under zero for an unsigned int.
+ break;
+ }
+
+ glyphIndex -= numberOfGLyphsInGroup;
+ }
+ }
+ else
+ {
+ lineLayout = currentLineLayout;
+
+ AdjustLayout( parameters,
+ bidiParameters,
+ bidirectionalParagraphInfo,
+ lineLayout );
+ }
+ }
+ else
+ {
+ lineLayout.length = length;
+ }
+ }
+ }
+ }
+ }
+
+ void AdjustLayout( const Parameters& parameters,
+ LayoutBidiParameters& bidiParameters,
+ const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo,
+ LineLayout& lineLayout )
+ {
+ Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = parameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+ // Remove current reordered line.
+ bidirectionalLinesInfo.Erase( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+ // Re-build the conversion table without the removed glyphs.
+ ReorderLine( bidirectionalParagraphInfo,
+ bidirectionalLinesInfo,
+ bidiParameters.bidiLineIndex,
+ lineLayout.characterIndex,
+ lineLayout.numberOfCharacters,
+ bidiParameters.paragraphDirection );
+
+ const BidirectionalLineInfoRun& bidirectionalLineInfo = *( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+ float length = 0.f;
+ float whiteSpaceLengthEndOfLine = 0.f;
+ LayoutRightToLeft( parameters,
+ bidirectionalLineInfo,
+ length,
+ whiteSpaceLengthEndOfLine );
+
+ lineLayout.length = length;
+ lineLayout.whiteSpaceLengthEndOfLine = whiteSpaceLengthEndOfLine;
+ }
+