15894466122cb537cd08c212e3febd59d28ffdec
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <dali/public-api/math/vector2.h>
24 #include <dali/public-api/text-abstraction/font-client.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
29 #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
30
31 namespace Dali
32 {
33
34 namespace Toolkit
35 {
36
37 namespace Text
38 {
39
40 namespace
41 {
42
43 #if defined(DEBUG_ENABLED)
44   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
45 #endif
46
47 const float MAX_FLOAT = std::numeric_limits<float>::max();
48 const bool RTL = true;
49
50 } //namespace
51
52 /**
53  * @brief Stores temporary layout info of the line.
54  */
55 struct LineLayout
56 {
57   LineLayout()
58   : glyphIndex( 0u ),
59     characterIndex( 0u ),
60     numberOfGlyphs( 0u ),
61     numberOfCharacters( 0u ),
62     length( 0.f ),
63     widthAdvanceDiff( 0.f ),
64     wsLengthEndOfLine( 0.f ),
65     ascender( 0.f ),
66     descender( MAX_FLOAT )
67   {}
68
69   ~LineLayout()
70   {}
71
72   void Clear()
73   {
74     glyphIndex = 0u;
75     characterIndex = 0u;
76     numberOfGlyphs = 0u;
77     numberOfCharacters = 0u;
78     length = 0.f;
79     widthAdvanceDiff = 0.f;
80     wsLengthEndOfLine = 0.f;
81     ascender = 0.f;
82     descender = MAX_FLOAT;
83   }
84
85   GlyphIndex     glyphIndex;         ///< Index of the first glyph to be laid-out.
86   CharacterIndex characterIndex;     ///< Index of the first character to be laid-out.
87   Length         numberOfGlyphs;     ///< The number of glyph which fit in one line.
88   Length         numberOfCharacters; ///< The number of characters which fit in one line.
89   float          length;             ///< The length of the glyphs which fit in one line.
90   float          widthAdvanceDiff;   ///< The difference between the xBearing + width and the advance of the last glyph.
91   float          wsLengthEndOfLine;  ///< The length of the white spaces at the end of the line.
92   float          ascender;           ///< The maximum ascender of all fonts in the line.
93   float          descender;          ///< The minimum descender of all fonts in the line.
94 };
95
96 struct LayoutEngine::Impl
97 {
98   Impl()
99   : mLayout( LayoutEngine::SINGLE_LINE_BOX ),
100     mHorizontalAlignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN ),
101     mVerticalAlignment( LayoutEngine::VERTICAL_ALIGN_TOP )
102   {
103     mFontClient = TextAbstraction::FontClient::Get();
104   }
105
106   /**
107    * @brief Updates the line ascender and descender with the metrics of a new font.
108    *
109    * @param[in] fontId The id of the new font.
110    * @param[in,out] lineLayout The line layout.
111    */
112   void UpdateLineHeight( FontId fontId, LineLayout& lineLayout )
113   {
114     Text::FontMetrics fontMetrics;
115     mFontClient.GetFontMetrics( fontId, fontMetrics );
116
117     // Sets the maximum ascender.
118     if( fontMetrics.ascender > lineLayout.ascender )
119     {
120       lineLayout.ascender = fontMetrics.ascender;
121     }
122
123     // Sets the minimum descender.
124     if( fontMetrics.descender < lineLayout.descender )
125     {
126       lineLayout.descender = fontMetrics.descender;
127     }
128   }
129
130   /**
131    * @brief Merges a temporary line layout into the line layout.
132    *
133    * @param[in,out] lineLayout The line layout.
134    * @param[in] tmpLineLayout A temporary line layout.
135    */
136   void MergeLineLayout( LineLayout& lineLayout,
137                         const LineLayout& tmpLineLayout )
138   {
139     lineLayout.numberOfCharacters += tmpLineLayout.numberOfCharacters;
140     lineLayout.numberOfGlyphs += tmpLineLayout.numberOfGlyphs;
141     lineLayout.length += tmpLineLayout.length;
142
143     if( 0.f < tmpLineLayout.length )
144     {
145       lineLayout.length += lineLayout.wsLengthEndOfLine;
146
147       lineLayout.wsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine;
148       lineLayout.widthAdvanceDiff = tmpLineLayout.widthAdvanceDiff;
149     }
150     else
151     {
152       lineLayout.wsLengthEndOfLine += tmpLineLayout.wsLengthEndOfLine;
153     }
154
155     if( tmpLineLayout.ascender > lineLayout.ascender )
156     {
157       lineLayout.ascender = tmpLineLayout.ascender;
158     }
159
160     if( tmpLineLayout.descender < lineLayout.descender )
161     {
162       lineLayout.descender = tmpLineLayout.descender;
163     }
164   }
165
166   /**
167    * Retrieves the line layout for a given box width.
168    */
169   void GetLineLayoutForBox( const LayoutParameters& parameters,
170                             LineLayout& lineLayout )
171   {
172     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n" );
173     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  initial glyph index : %d\n", lineLayout.glyphIndex );
174     // Stores temporary line layout which has not been added to the final line layout.
175     LineLayout tmpLineLayout;
176
177     const bool isMultiline = mLayout == MULTI_LINE_BOX;
178     const GlyphIndex lastGlyphIndex = parameters.totalNumberOfGlyphs - 1u;
179
180     // If the first glyph has a negative bearing its absolute value needs to be added to the line length.
181     // In the case the line starts with a right to left character the bearing needs to be substracted to the line length.
182     const GlyphInfo& glyphInfo = *( parameters.glyphsBuffer + lineLayout.glyphIndex );
183     float initialHorizontalBearing = glyphInfo.xBearing;
184
185     lineLayout.characterIndex = *( parameters.glyphsToCharactersBuffer + lineLayout.glyphIndex );
186     const CharacterDirection firstCharacterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + lineLayout.characterIndex );
187
188     if( RTL == firstCharacterDirection )
189     {
190       initialHorizontalBearing = -initialHorizontalBearing;
191
192       if( 0.f < glyphInfo.xBearing )
193       {
194         tmpLineLayout.length = glyphInfo.xBearing;
195         initialHorizontalBearing = 0.f;
196       }
197     }
198     else
199     {
200       if( 0.f > glyphInfo.xBearing )
201       {
202         tmpLineLayout.length = -glyphInfo.xBearing;
203         initialHorizontalBearing = 0.f;
204       }
205     }
206
207     // Calculate the line height if there is no characters.
208     FontId lastFontId = glyphInfo.fontId;
209     UpdateLineHeight( lastFontId, tmpLineLayout );
210
211     const float boundingBoxWidth = parameters.boundingBox.width - initialHorizontalBearing;
212
213     bool oneWordLaidOut = false;
214
215     for( GlyphIndex glyphIndex = lineLayout.glyphIndex;
216          glyphIndex < parameters.totalNumberOfGlyphs;
217          ++glyphIndex )
218     {
219       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  glyph index : %d\n", glyphIndex );
220       const bool isLastGlyph = glyphIndex == lastGlyphIndex;
221
222       // Get the glyph info.
223       const GlyphInfo& glyphInfo = *( parameters.glyphsBuffer + glyphIndex );
224
225       // Get the character indices for the current glyph. The last character index is needed
226       // because there are glyphs formed by more than one character but their break info is
227       // given only for the last character.
228       const Length charactersPerGlyph = *( parameters.charactersPerGlyphBuffer + glyphIndex );
229       const CharacterIndex characterFirstIndex = *( parameters.glyphsToCharactersBuffer + glyphIndex );
230       const CharacterIndex characterLastIndex = characterFirstIndex + ( ( 1u > charactersPerGlyph ) ? 0u : charactersPerGlyph - 1u );
231
232       // Get the line break info for the current character.
233       const LineBreakInfo lineBreakInfo = *( parameters.lineBreakInfoBuffer + characterLastIndex );
234
235       // Get the word break info for the current character.
236       const WordBreakInfo wordBreakInfo = *( parameters.wordBreakInfoBuffer + characterLastIndex );
237
238       // Increase the number of characters.
239       tmpLineLayout.numberOfCharacters += charactersPerGlyph;
240
241       // Increase the number of glyphs.
242       tmpLineLayout.numberOfGlyphs++;
243
244       // Check whether is a white space.
245       const Character character = *( parameters.textBuffer + characterFirstIndex );
246       const bool isWhiteSpace = TextAbstraction::IsWhiteSpace( character );
247
248       // Used to restore the temporal line layout when a single word does not fit in the control's width and is split by character.
249       const float previousTmpLineLength = tmpLineLayout.length;
250       const float previousTmpWidthAdvanceDiff = tmpLineLayout.widthAdvanceDiff;
251
252       // Increase the accumulated length.
253       if( isWhiteSpace )
254       {
255         // Add the length to the length of white spaces at the end of the line.
256         tmpLineLayout.wsLengthEndOfLine += glyphInfo.advance; // The advance is used as the width is always zero for the white spaces.
257       }
258       else
259       {
260         // Add as well any previous white space length.
261         tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine + glyphInfo.advance;
262         if( RTL == firstCharacterDirection )
263         {
264           tmpLineLayout.widthAdvanceDiff = -glyphInfo.xBearing;
265         }
266         else
267         {
268           tmpLineLayout.widthAdvanceDiff = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
269         }
270
271         // Clear the white space length at the end of the line.
272         tmpLineLayout.wsLengthEndOfLine = 0.f;
273       }
274
275       // Check if the accumulated length fits in the width of the box.
276       if( isMultiline && !isWhiteSpace &&
277           ( lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpLineLayout.widthAdvanceDiff > boundingBoxWidth ) )
278       {
279         // Current word does not fit in the box's width.
280         if( !oneWordLaidOut )
281         {
282           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Break the word by character\n" );
283
284           // The word's with doesn't fit in the control's with. It needs to be split by character.
285           if( tmpLineLayout.numberOfGlyphs > 1u )
286           {
287             tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
288             --tmpLineLayout.numberOfGlyphs;
289             tmpLineLayout.length = previousTmpLineLength;
290             tmpLineLayout.widthAdvanceDiff = previousTmpWidthAdvanceDiff;
291           }
292
293           // Add part of the word to the line layout.
294           MergeLineLayout( lineLayout, tmpLineLayout );
295         }
296         else
297         {
298           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Current word does not fit.\n" );
299         }
300         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
301         return;
302       }
303
304       if( ( isMultiline || isLastGlyph ) &&
305           ( TextAbstraction::LINE_MUST_BREAK == lineBreakInfo ) )
306       {
307         // Must break the line. Update the line layout and return.
308         MergeLineLayout( lineLayout, tmpLineLayout );
309
310         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
311         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
312         return;
313       }
314
315       if( isMultiline &&
316           ( TextAbstraction::WORD_BREAK == wordBreakInfo ) )
317       {
318         oneWordLaidOut = true;
319         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  One word laid out\n" );
320
321         // Current glyph is the last one of the current word.
322         // Add the temporal layout to the current one.
323         MergeLineLayout( lineLayout, tmpLineLayout );
324
325         tmpLineLayout.Clear();
326       }
327
328       // Check if the font of the current glyph is the same of the previous one.
329       // If it's different the ascender and descender need to be updated.
330       if( lastFontId != glyphInfo.fontId )
331       {
332         UpdateLineHeight( glyphInfo.fontId, tmpLineLayout );
333         lastFontId = glyphInfo.fontId;
334       }
335     }
336     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
337   }
338
339   bool LayoutText( const LayoutParameters& layoutParameters,
340                    Vector<Vector2>& glyphPositions,
341                    Vector<LineRun>& lines,
342                    Size& actualSize )
343   {
344     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->LayoutText\n" );
345     Vector2* glyphPositionsBuffer = glyphPositions.Begin();
346
347     float penY = 0.f;
348     for( GlyphIndex index = 0u; index < layoutParameters.totalNumberOfGlyphs; )
349     {
350       // Get the layout for the line.
351       LineLayout layout;
352       layout.glyphIndex = index;
353       GetLineLayoutForBox( layoutParameters,
354                            layout );
355
356       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex );
357       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "       character index %d\n", layout.characterIndex );
358       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "      number of glyphs %d\n", layout.numberOfGlyphs );
359       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of characters %d\n", layout.numberOfCharacters );
360       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                length %f\n", layout.length );
361
362       if( 0u == layout.numberOfGlyphs )
363       {
364         // The width is too small and no characters are laid-out.
365         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n" );
366         return false;
367       }
368
369       LineRun lineRun;
370       lineRun.glyphIndex = index;
371       lineRun.numberOfGlyphs = layout.numberOfGlyphs;
372       lineRun.characterRun.characterIndex = layout.characterIndex;
373       lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
374       lineRun.width = layout.length + layout.widthAdvanceDiff;
375       lineRun.ascender = layout.ascender;
376       lineRun.descender = layout.descender;
377       lineRun.extraLength = layout.wsLengthEndOfLine > 0.f ? layout.wsLengthEndOfLine - layout.widthAdvanceDiff : 0.f;
378       lineRun.direction = false;
379
380       lines.PushBack( lineRun );
381
382       // Update the actual size.
383       if( lineRun.width > actualSize.width )
384       {
385         actualSize.width = lineRun.width;
386       }
387
388       actualSize.height += ( lineRun.ascender + -lineRun.descender );
389
390       // Traverse the glyphs and set the positions.
391
392       penY += layout.ascender;
393
394       // Check if the x bearing of the first character is negative.
395       // If it has a negative x bearing, it will exceed the boundaries of the actor,
396       // so the penX position needs to be moved to the right.
397       float penX = 0.f;
398
399       const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + index );
400       if( 0.f > glyph.xBearing )
401       {
402         penX = -glyph.xBearing;
403       }
404
405       for( GlyphIndex i = index; i < index + layout.numberOfGlyphs; ++i )
406       {
407         const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + i );
408         Vector2& position = *( glyphPositionsBuffer + i );
409
410         position.x = penX + glyph.xBearing;
411         position.y = penY - glyph.yBearing;
412
413         penX += glyph.advance;
414       }
415
416       penY += -layout.descender;
417
418       // Increase the glyph index.
419       index += layout.numberOfGlyphs;
420     }
421
422     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
423     return true;
424   }
425
426   void ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
427                                  Vector<Vector2>& glyphPositions )
428   {
429     // Traverses the paragraphs with right to left characters.
430     for( LineIndex lineIndex = 0u; lineIndex < layoutParameters.numberOfBidirectionalInfoRuns; ++lineIndex )
431     {
432       const BidirectionalLineInfoRun& bidiLine = *( layoutParameters.lineBidirectionalInfoRunsBuffer + lineIndex );
433
434       float penX = 0.f;
435
436       const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *bidiLine.visualToLogicalMap;
437       const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
438
439       penX = -glyph.xBearing;
440
441       Vector2* glyphPositionsBuffer = glyphPositions.Begin();
442
443       // Traverses the characters of the right to left paragraph.
444       for( CharacterIndex characterLogicalIndex = 0u;
445            characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
446            ++characterLogicalIndex )
447       {
448         // Convert the character in the logical order into the character in the visual order.
449         const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
450
451         // Get the number of glyphs of the character.
452         const Length numberOfGlyphs = *( layoutParameters.glyphsPerCharacterBuffer + characterVisualIndex );
453
454         for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
455         {
456           // Convert the character in the visual order into the glyph in the visual order.
457           const GlyphIndex glyphIndex = *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) + index;
458
459           DALI_ASSERT_DEBUG( 0u <= glyphIndex && glyphIndex < layoutParameters.totalNumberOfGlyphs );
460
461           const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + glyphIndex );
462           Vector2& position = *( glyphPositionsBuffer + glyphIndex );
463
464           position.x = penX + glyph.xBearing;
465           penX += glyph.advance;
466         }
467       }
468     }
469   }
470
471   void Align( const LayoutParameters& layoutParameters,
472               const Size& layoutSize,
473               const Vector<LineRun>& lines,
474               Vector<Vector2>& glyphPositions )
475   {
476     Vector2* glyphPositionsBuffer = glyphPositions.Begin();
477
478     // Traverse all lines and align the glyphs.
479     // LayoutParameters contains bidirectional info for those lines with
480     // right to left text, this info includes the paragraph's direction.
481
482     LineIndex bidiLineIndex = 0u;
483     for( Vector<LineRun>::ConstIterator it = lines.Begin(), endIt = lines.End();
484          it != endIt;
485          ++it )
486     {
487       const LineRun& line = *it;
488
489       // 1) Get the paragrap's direction.
490       bool paragraphDirection = false;
491
492       // Check if there is any right to left line.
493       if( ( NULL != layoutParameters.lineBidirectionalInfoRunsBuffer ) &&
494           ( bidiLineIndex < layoutParameters.numberOfBidirectionalInfoRuns ) )
495       {
496         const BidirectionalLineInfoRun* bidiLine = layoutParameters.lineBidirectionalInfoRunsBuffer + bidiLineIndex;
497
498         // Get the right to left line that match with current line.
499         while( ( line.characterRun.characterIndex > bidiLine->characterRun.characterIndex ) &&
500                ( bidiLineIndex < layoutParameters.numberOfBidirectionalInfoRuns ) )
501         {
502           ++bidiLineIndex;
503           bidiLine = layoutParameters.lineBidirectionalInfoRunsBuffer + bidiLineIndex;
504         }
505
506         if( line.characterRun.characterIndex == bidiLine->characterRun.characterIndex )
507         {
508           paragraphDirection = bidiLine->direction;
509         }
510       }
511
512       // 2) Calculate the alignment offset accordingly with the align option,
513       //    the box width, line length, and the paragraphs direction.
514       float alignOffset = CalculateHorizontalAlignment( layoutSize.width,
515                                                         line.width,
516                                                         line.extraLength,
517                                                         paragraphDirection );
518
519       // 3) Traverse all glyphs and update the 'x' position.
520       for( GlyphIndex index = line.glyphIndex,
521              endIndex = line.glyphIndex + line.numberOfGlyphs;
522            index < endIndex;
523            ++index )
524       {
525         Vector2& position = *( glyphPositionsBuffer + index );
526
527         position.x += alignOffset;
528       }
529     }
530   }
531
532   float CalculateHorizontalAlignment( float boxWidth,
533                                       float lineLength,
534                                       float extraLength,
535                                       bool paragraphDirection )
536   {
537     float offset = 0.f;
538
539     HorizontalAlignment alignment = mHorizontalAlignment;
540     if( paragraphDirection &&
541         ( HORIZONTAL_ALIGN_CENTER != alignment ) )
542     {
543       if( HORIZONTAL_ALIGN_BEGIN == alignment )
544       {
545         alignment = HORIZONTAL_ALIGN_END;
546       }
547       else
548       {
549         alignment = HORIZONTAL_ALIGN_BEGIN;
550       }
551     }
552
553     switch( alignment )
554     {
555       case HORIZONTAL_ALIGN_BEGIN:
556       {
557         offset = 0.f;
558         break;
559       }
560       case HORIZONTAL_ALIGN_CENTER:
561       {
562         offset = 0.5f * ( boxWidth - lineLength );
563         const int intOffset = static_cast<int>( offset ); // try to avoid pixel alignment.
564         offset = static_cast<float>( intOffset );
565         break;
566       }
567       case HORIZONTAL_ALIGN_END:
568       {
569         offset = boxWidth - lineLength;
570         break;
571       }
572     }
573
574     if( paragraphDirection )
575     {
576       offset -= extraLength;
577     }
578
579     return offset;
580   }
581
582   LayoutEngine::Layout mLayout;
583   LayoutEngine::HorizontalAlignment mHorizontalAlignment;
584   LayoutEngine::VerticalAlignment mVerticalAlignment;
585
586   TextAbstraction::FontClient mFontClient;
587 };
588
589 LayoutEngine::LayoutEngine()
590 : mImpl( NULL )
591 {
592   mImpl = new LayoutEngine::Impl();
593 }
594
595 LayoutEngine::~LayoutEngine()
596 {
597   delete mImpl;
598 }
599
600 void LayoutEngine::SetLayout( Layout layout )
601 {
602   mImpl->mLayout = layout;
603 }
604
605 unsigned int LayoutEngine::GetLayout() const
606 {
607   return mImpl->mLayout;
608 }
609
610 void LayoutEngine::SetHorizontalAlignment( HorizontalAlignment alignment )
611 {
612   mImpl->mHorizontalAlignment = alignment;
613 }
614
615 LayoutEngine::HorizontalAlignment LayoutEngine::GetHorizontalAlignment() const
616 {
617   return mImpl->mHorizontalAlignment;
618 }
619
620 void LayoutEngine::SetVerticalAlignment( VerticalAlignment alignment )
621 {
622   mImpl->mVerticalAlignment = alignment;
623 }
624
625 LayoutEngine::VerticalAlignment LayoutEngine::GetVerticalAlignment() const
626 {
627   return mImpl->mVerticalAlignment;
628 }
629
630 bool LayoutEngine::LayoutText( const LayoutParameters& layoutParameters,
631                                Vector<Vector2>& glyphPositions,
632                                Vector<LineRun>& lines,
633                                Size& actualSize )
634 {
635   return mImpl->LayoutText( layoutParameters,
636                             glyphPositions,
637                             lines,
638                             actualSize );
639 }
640
641 void LayoutEngine::ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
642                                              Vector<Vector2>& glyphPositions )
643 {
644   mImpl->ReLayoutRightToLeftLines( layoutParameters,
645                                    glyphPositions );
646 }
647
648 void LayoutEngine::Align( const LayoutParameters& layoutParameters,
649                           const Size& layoutSize,
650                           const Vector<LineRun>& lines,
651                           Vector<Vector2>& glyphPositions )
652 {
653   mImpl->Align( layoutParameters,
654                 layoutSize,
655                 lines,
656                 glyphPositions );
657 }
658
659 } // namespace Text
660
661 } // namespace Toolkit
662
663 } // namespace Dali