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