Merge "Disable pixel alignment while scrolling the text" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
1 /*
2  * Copyright (c) 2017 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/integration-api/debug.h>
24 #include <dali/devel-api/text-abstraction/font-client.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
28 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
29 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
30 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
31
32 namespace Dali
33 {
34
35 namespace Toolkit
36 {
37
38 namespace Text
39 {
40
41 namespace Layout
42 {
43
44 namespace
45 {
46
47 #if defined(DEBUG_ENABLED)
48   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
49 #endif
50
51 const float MAX_FLOAT = std::numeric_limits<float>::max();
52 const bool RTL = true;
53 const float CURSOR_WIDTH = 1.f;
54 const float LINE_SPACING= 0.f;
55
56 } //namespace
57
58 /**
59  * @brief Stores temporary layout info of the line.
60  */
61 struct LineLayout
62 {
63   LineLayout()
64   : glyphIndex( 0u ),
65     characterIndex( 0u ),
66     numberOfGlyphs( 0u ),
67     numberOfCharacters( 0u ),
68     length( 0.f ),
69     extraBearing( 0.f ),
70     extraWidth( 0.f ),
71     wsLengthEndOfLine( 0.f ),
72     ascender( 0.f ),
73     descender( MAX_FLOAT ),
74     lineSpacing( 0.f )
75   {}
76
77   ~LineLayout()
78   {}
79
80   void Clear()
81   {
82     glyphIndex = 0u;
83     characterIndex = 0u;
84     numberOfGlyphs = 0u;
85     numberOfCharacters = 0u;
86     length = 0.f;
87     extraBearing = 0.f;
88     extraWidth = 0.f;
89     wsLengthEndOfLine = 0.f;
90     ascender = 0.f;
91     descender = MAX_FLOAT;
92   }
93
94   GlyphIndex     glyphIndex;         ///< Index of the first glyph to be laid-out.
95   CharacterIndex characterIndex;     ///< Index of the first character to be laid-out.
96   Length         numberOfGlyphs;     ///< The number of glyph which fit in one line.
97   Length         numberOfCharacters; ///< The number of characters which fit in one line.
98   float          length;             ///< The addition of the advance metric of all the glyphs which fit in one line.
99   float          extraBearing;       ///< The extra width to be added to the line's length when the bearing of the first glyph is negative.
100   float          extraWidth;         ///< The extra width to be added to the line's length when the bearing + width of the last glyph is greater than the advance.
101   float          wsLengthEndOfLine;  ///< The length of the white spaces at the end of the line.
102   float          ascender;           ///< The maximum ascender of all fonts in the line.
103   float          descender;          ///< The minimum descender of all fonts in the line.
104   float          lineSpacing;        ///< The line spacing
105 };
106
107 struct Engine::Impl
108 {
109   Impl()
110   : mLayout( Layout::Engine::SINGLE_LINE_BOX ),
111     mCursorWidth( CURSOR_WIDTH ),
112     mDefaultLineSpacing( LINE_SPACING )
113   {
114   }
115
116   /**
117    * @brief Updates the line ascender and descender with the metrics of a new font.
118    *
119    * @param[in] fontId The id of the new font.
120    * @param[in,out] lineLayout The line layout.
121    */
122   void UpdateLineHeight( FontId fontId, LineLayout& lineLayout )
123   {
124     Text::FontMetrics fontMetrics;
125     mMetrics->GetFontMetrics( fontId, fontMetrics );
126
127     // Sets the maximum ascender.
128     if( fontMetrics.ascender > lineLayout.ascender )
129     {
130       lineLayout.ascender = fontMetrics.ascender;
131     }
132
133     // Sets the minimum descender.
134     if( fontMetrics.descender < lineLayout.descender )
135     {
136       lineLayout.descender = fontMetrics.descender;
137     }
138
139     // set the line spacing
140     lineLayout.lineSpacing = mDefaultLineSpacing;
141   }
142
143   /**
144    * @brief Merges a temporary line layout into the line layout.
145    *
146    * @param[in,out] lineLayout The line layout.
147    * @param[in] tmpLineLayout A temporary line layout.
148    */
149   void MergeLineLayout( LineLayout& lineLayout,
150                         const LineLayout& tmpLineLayout )
151   {
152     lineLayout.numberOfCharacters += tmpLineLayout.numberOfCharacters;
153     lineLayout.numberOfGlyphs += tmpLineLayout.numberOfGlyphs;
154     lineLayout.length += tmpLineLayout.length;
155
156     if( 0.f < tmpLineLayout.length )
157     {
158       lineLayout.length += lineLayout.wsLengthEndOfLine;
159
160       lineLayout.wsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine;
161     }
162     else
163     {
164       lineLayout.wsLengthEndOfLine += tmpLineLayout.wsLengthEndOfLine;
165     }
166
167     if( tmpLineLayout.ascender > lineLayout.ascender )
168     {
169       lineLayout.ascender = tmpLineLayout.ascender;
170     }
171
172     if( tmpLineLayout.descender < lineLayout.descender )
173     {
174       lineLayout.descender = tmpLineLayout.descender;
175     }
176   }
177
178   /**
179    * Retrieves the line layout for a given box width.
180    *
181    * @note This method lais out text as it were left to right. At this point is not possible to reorder the line
182    *       because the number of characters of the line is not known (one of the responsabilities of this method
183    *       is calculate that). Due to glyph's 'x' bearing, width and advance, when right to left or mixed right to left
184    *       and left to right text is laid-out, it can be small differences in the line length. One solution is to
185    *       reorder and re-lay out the text after this method and add or remove one extra glyph if needed. However,
186    *       this method calculates which are the first and last glyphs of the line (the ones that causes the
187    *       differences). This is a good point to check if there is problems with the text exceeding the boundaries
188    *       of the control when there is right to left text.
189    *
190    * @param[in] parameters The layout parameters.
191    * @param[out] lineLayout The line layout.
192    * @param[in,out] paragraphDirection in: the current paragraph's direction, out: the next paragraph's direction. Is set after a must break.
193    * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ).
194    */
195   void GetLineLayoutForBox( const Parameters& parameters,
196                             LineLayout& lineLayout,
197                             CharacterDirection& paragraphDirection,
198                             bool completelyFill )
199   {
200     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n" );
201     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  initial glyph index : %d\n", lineLayout.glyphIndex );
202     // Stores temporary line layout which has not been added to the final line layout.
203     LineLayout tmpLineLayout;
204
205     const bool isMultiline = mLayout == MULTI_LINE_BOX;
206     const bool isWordLaidOut = parameters.lineWrapMode == Text::LineWrap::WORD;
207
208     // The last glyph to be laid-out.
209     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
210
211     // If the first glyph has a negative bearing its absolute value needs to be added to the line length.
212     // In the case the line starts with a right to left character, if the width is longer than the advance,
213     // the difference needs to be added to the line length.
214
215     // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
216     const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( lineLayout.glyphIndex,
217                                                                    lastGlyphOfParagraphPlusOne,
218                                                                    parameters.charactersPerGlyphBuffer );
219
220     GlyphMetrics glyphMetrics;
221     GetGlyphsMetrics( lineLayout.glyphIndex,
222                       numberOfGLyphsInGroup,
223                       glyphMetrics,
224                       parameters.glyphsBuffer,
225                       mMetrics );
226
227     // Set the direction of the first character of the line.
228     lineLayout.characterIndex = *( parameters.glyphsToCharactersBuffer + lineLayout.glyphIndex );
229     const CharacterDirection firstCharacterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + lineLayout.characterIndex );
230     CharacterDirection previousCharacterDirection = firstCharacterDirection;
231
232     const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
233     float tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
234
235     float tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
236
237     tmpLineLayout.length += mCursorWidth; // Added to give some space to the cursor.
238
239     // Calculate the line height if there is no characters.
240     FontId lastFontId = glyphMetrics.fontId;
241     UpdateLineHeight( lastFontId, tmpLineLayout );
242
243     bool oneWordLaidOut = false;
244
245     for( GlyphIndex glyphIndex = lineLayout.glyphIndex;
246          glyphIndex < lastGlyphOfParagraphPlusOne; )
247     {
248       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  glyph index : %d\n", glyphIndex );
249
250       // Check whether this glyph comes from a character that is shaped in multiple glyphs.
251       const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
252                                                                      lastGlyphOfParagraphPlusOne,
253                                                                      parameters.charactersPerGlyphBuffer );
254
255       GlyphMetrics glyphMetrics;
256       GetGlyphsMetrics( glyphIndex,
257                         numberOfGLyphsInGroup,
258                         glyphMetrics,
259                         parameters.glyphsBuffer,
260                         mMetrics );
261
262       const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup  == parameters.totalNumberOfGlyphs;
263
264       // Check if the font of the current glyph is the same of the previous one.
265       // If it's different the ascender and descender need to be updated.
266       if( lastFontId != glyphMetrics.fontId )
267       {
268         UpdateLineHeight( glyphMetrics.fontId, tmpLineLayout );
269         lastFontId = glyphMetrics.fontId;
270       }
271
272       // Get the character indices for the current glyph. The last character index is needed
273       // because there are glyphs formed by more than one character but their break info is
274       // given only for the last character.
275       const Length charactersPerGlyph = *( parameters.charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
276       const bool hasCharacters = charactersPerGlyph > 0u;
277       const CharacterIndex characterFirstIndex = *( parameters.glyphsToCharactersBuffer + glyphIndex );
278       const CharacterIndex characterLastIndex = characterFirstIndex + ( hasCharacters ? charactersPerGlyph - 1u : 0u );
279
280       // Get the line break info for the current character.
281       const LineBreakInfo lineBreakInfo = hasCharacters ? *( parameters.lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
282
283       // Get the word break info for the current character.
284       const WordBreakInfo wordBreakInfo = *( parameters.wordBreakInfoBuffer + characterLastIndex );
285
286       // Increase the number of characters.
287       tmpLineLayout.numberOfCharacters += charactersPerGlyph;
288
289       // Increase the number of glyphs.
290       tmpLineLayout.numberOfGlyphs += numberOfGLyphsInGroup;
291
292       // Check whether is a white space.
293       const Character character = *( parameters.textBuffer + characterFirstIndex );
294       const bool isWhiteSpace = TextAbstraction::IsWhiteSpace( character );
295
296       // Used to restore the temporal line layout when a single word does not fit in the control's width and is split by character.
297       const float previousTmpLineLength = tmpLineLayout.length;
298       const float previousTmpExtraBearing = tmpExtraBearing;
299       const float previousTmpExtraWidth = tmpExtraWidth;
300
301       // Get the character's direction.
302       const CharacterDirection characterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + characterFirstIndex );
303
304       // Increase the accumulated length.
305       if( isWhiteSpace )
306       {
307         // Add the length to the length of white spaces at the end of the line.
308         tmpLineLayout.wsLengthEndOfLine += glyphMetrics.advance; // The advance is used as the width is always zero for the white spaces.
309       }
310       else
311       {
312         // Add as well any previous white space length.
313         tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine + glyphMetrics.advance;
314
315         // An extra space may be added to the line for the first and last glyph of the line.
316         // If the bearing of the first glyph is negative, its positive value needs to be added.
317         // If the bearing plus the width of the last glyph is greater than the advance, the difference
318         // needs to be added.
319
320         if( characterDirection == paragraphDirection )
321         {
322           if( RTL == characterDirection )
323           {
324             //       <--
325             // |   Rrrrr|
326             // or
327             // |  Rllrrr|
328             // or
329             // |lllrrrrr|
330             // |     Rll|
331             //
332
333             tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
334           }
335           else // LTR
336           {
337             //  -->
338             // |lllL    |
339             // or
340             // |llrrL   |
341             // or
342             // |lllllrrr|
343             // |rrL     |
344             //
345
346             const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
347             tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
348           }
349         }
350         else
351         {
352           if( characterDirection != previousCharacterDirection )
353           {
354             if( RTL == characterDirection )
355             {
356               //  -->
357               // |lllR    |
358
359               const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
360               tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
361             }
362             else // LTR
363             {
364               //       <--
365               // |   Lrrrr|
366
367               tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
368             }
369           }
370           else if( characterDirection == firstCharacterDirection )
371           {
372             if( RTL == characterDirection )
373             {
374               //  -->
375               // |llllllrr|
376               // |Rr      |
377
378               tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
379             }
380             else // LTR
381             {
382               //       <--
383               // |llllrrrr|
384               // |     llL|
385
386               const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
387               tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
388             }
389           }
390         }
391
392         // Clear the white space length at the end of the line.
393         tmpLineLayout.wsLengthEndOfLine = 0.f;
394       }
395
396       // Check if the accumulated length fits in the width of the box.
397       if( ( completelyFill || isMultiline ) && !isWhiteSpace &&
398           ( tmpExtraBearing + lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpExtraWidth > parameters.boundingBox.width ) )
399       {
400         // Current word does not fit in the box's width.
401         if( !oneWordLaidOut || completelyFill )
402         {
403           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Break the word by character\n" );
404
405           // The word doesn't fit in the control's width. It needs to be split by character.
406           if( tmpLineLayout.numberOfGlyphs > 0u )
407           {
408             tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
409             tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
410             tmpLineLayout.length = previousTmpLineLength;
411             tmpExtraBearing = previousTmpExtraBearing;
412             tmpExtraWidth = previousTmpExtraWidth;
413           }
414
415           // Add part of the word to the line layout.
416           MergeLineLayout( lineLayout, tmpLineLayout );
417         }
418         else
419         {
420           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Current word does not fit.\n" );
421         }
422
423         lineLayout.extraBearing = tmpExtraBearing;
424         lineLayout.extraWidth = tmpExtraWidth;
425
426         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox.\n" );
427
428         return;
429       }
430
431       if( ( isMultiline || isLastGlyph ) &&
432           ( TextAbstraction::LINE_MUST_BREAK == lineBreakInfo ) )
433       {
434         // Must break the line. Update the line layout and return.
435         MergeLineLayout( lineLayout, tmpLineLayout );
436
437         // Set the next paragraph's direction.
438         if( !isLastGlyph &&
439             ( NULL != parameters.characterDirectionBuffer ) )
440         {
441           paragraphDirection = *( parameters.characterDirectionBuffer + 1u + characterLastIndex );
442         }
443
444         lineLayout.extraBearing = tmpExtraBearing;
445         lineLayout.extraWidth = tmpExtraWidth;
446
447         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
448         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
449
450         return;
451       }
452
453       if( isMultiline &&
454           ( TextAbstraction::WORD_BREAK == wordBreakInfo ) )
455       {
456         oneWordLaidOut = isWordLaidOut;
457         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  One word laid-out\n" );
458
459         // Current glyph is the last one of the current word.
460         // Add the temporal layout to the current one.
461         MergeLineLayout( lineLayout, tmpLineLayout );
462
463         tmpLineLayout.Clear();
464       }
465
466       previousCharacterDirection = characterDirection;
467       glyphIndex += numberOfGLyphsInGroup;
468     }
469
470     lineLayout.extraBearing = tmpExtraBearing;
471     lineLayout.extraWidth = tmpExtraWidth;
472
473     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
474   }
475
476   void SetGlyphPositions( const GlyphInfo* const glyphsBuffer,
477                           Length numberOfGlyphs,
478                           float outlineWidth,
479                           Vector2* glyphPositionsBuffer )
480   {
481     // Traverse the glyphs and set the positions.
482
483     // Check if the x bearing of the first character is negative.
484     // If it has a negative x bearing, it will exceed the boundaries of the actor,
485     // so the penX position needs to be moved to the right.
486
487     const GlyphInfo& glyph = *glyphsBuffer;
488     float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing + outlineWidth : outlineWidth;
489
490
491     for( GlyphIndex i = 0u; i < numberOfGlyphs; ++i )
492     {
493       const GlyphInfo& glyph = *( glyphsBuffer + i );
494       Vector2& position = *( glyphPositionsBuffer + i );
495
496       position.x = penX + glyph.xBearing;
497       position.y = -glyph.yBearing;
498
499       penX += glyph.advance;
500     }
501   }
502
503   /**
504    * @brief Resizes the line buffer.
505    *
506    * @param[in,out] lines The vector of lines. Used when the layout is created from scratch.
507    * @param[in,out] newLines The vector of lines used instead of @p lines when the layout is updated.
508    * @param[in,out] linesCapacity The capacity of the vector (either lines or newLines).
509    * @param[in] updateCurrentBuffer Whether the layout is updated.
510    *
511    * @return Pointer to either lines or newLines.
512    */
513   LineRun* ResizeLinesBuffer( Vector<LineRun>& lines,
514                               Vector<LineRun>& newLines,
515                               Length& linesCapacity,
516                               bool updateCurrentBuffer )
517   {
518     LineRun* linesBuffer = NULL;
519     // Reserve more space for the next lines.
520     linesCapacity *= 2u;
521     if( updateCurrentBuffer )
522     {
523       newLines.Resize( linesCapacity );
524       linesBuffer = newLines.Begin();
525     }
526     else
527     {
528       lines.Resize( linesCapacity );
529       linesBuffer = lines.Begin();
530     }
531
532     return linesBuffer;
533   }
534
535   /**
536    * Ellipsis a line if it exceeds the width's of the bounding box.
537    *
538    * @param[in] layoutParameters The parameters needed to layout the text.
539    * @param[in] layout The line layout.
540    * @param[in,out] layoutSize The text's layout size.
541    * @param[in,out] linesBuffer Pointer to the line's buffer.
542    * @param[in,out] glyphPositionsBuffer Pointer to the position's buffer.
543    * @param[in,out] numberOfLines The number of laid-out lines.
544    * @param[in] penY The vertical layout position.
545    * @param[in] currentParagraphDirection The current paragraph's direction.
546    *
547    * return Whether the line is ellipsized.
548    */
549   bool EllipsisLine( const Parameters& layoutParameters,
550                      const LineLayout& layout,
551                      Size& layoutSize,
552                      LineRun* linesBuffer,
553                      Vector2* glyphPositionsBuffer,
554                      Length& numberOfLines,
555                      float penY,
556                      CharacterDirection currentParagraphDirection )
557   {
558     const bool ellipsis = ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
559                             ( ( mLayout == SINGLE_LINE_BOX ) &&
560                               ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) );
561
562     if( ellipsis )
563     {
564       // Do not layout more lines if ellipsis is enabled.
565
566       // The last line needs to be completely filled with characters.
567       // Part of a word may be used.
568
569       LineRun* lineRun = NULL;
570       LineLayout ellipsisLayout;
571       if( 0u != numberOfLines )
572       {
573         // Get the last line and layout it again with the 'completelyFill' flag to true.
574         lineRun = linesBuffer + ( numberOfLines - 1u );
575
576         penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
577
578         ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
579       }
580       else
581       {
582         // At least there is space reserved for one line.
583         lineRun = linesBuffer;
584
585         lineRun->glyphRun.glyphIndex = 0u;
586         ellipsisLayout.glyphIndex = 0u;
587
588         ++numberOfLines;
589       }
590
591       GetLineLayoutForBox( layoutParameters,
592                            ellipsisLayout,
593                            currentParagraphDirection,
594                            true );
595
596       lineRun->glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
597       lineRun->characterRun.characterIndex = ellipsisLayout.characterIndex;
598       lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
599       lineRun->width = ellipsisLayout.length;
600       lineRun->extraLength =  ( ellipsisLayout.wsLengthEndOfLine > 0.f ) ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.extraWidth : 0.f;
601       lineRun->ascender = ellipsisLayout.ascender;
602       lineRun->descender = ellipsisLayout.descender;
603       lineRun->direction = !RTL;
604       lineRun->ellipsis = true;
605
606       layoutSize.width = layoutParameters.boundingBox.width;
607       if( layoutSize.height < Math::MACHINE_EPSILON_1000 )
608       {
609         layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
610       }
611
612       SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
613                          ellipsisLayout.numberOfGlyphs,
614                          layoutParameters.outlineWidth,
615                          glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
616     }
617
618     return ellipsis;
619   }
620
621   /**
622    * @brief Updates the text layout with a new laid-out line.
623    *
624    * @param[in] layoutParameters The parameters needed to layout the text.
625    * @param[in] layout The line layout.
626    * @param[in,out] layoutSize The text's layout size.
627    * @param[in,out] linesBuffer Pointer to the line's buffer.
628    * @param[in] index Index to the vector of glyphs.
629    * @param[in,out] numberOfLines The number of laid-out lines.
630    * @param[in] isLastLine Whether the laid-out line is the last one.
631    */
632   void UpdateTextLayout( const Parameters& layoutParameters,
633                          const LineLayout& layout,
634                          Size& layoutSize,
635                          LineRun* linesBuffer,
636                          GlyphIndex index,
637                          Length& numberOfLines,
638                          bool isLastLine )
639   {
640     LineRun& lineRun = *( linesBuffer + numberOfLines );
641     ++numberOfLines;
642
643     lineRun.glyphRun.glyphIndex = index;
644     lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
645     lineRun.characterRun.characterIndex = layout.characterIndex;
646     lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
647     lineRun.lineSpacing = mDefaultLineSpacing;
648
649     if( isLastLine && !layoutParameters.isLastNewParagraph )
650     {
651       const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
652       if( MULTI_LINE_BOX == mLayout )
653       {
654         lineRun.width = ( width > layoutParameters.boundingBox.width ) ? layoutParameters.boundingBox.width : width;
655       }
656       else
657       {
658         lineRun.width = width;
659       }
660
661       lineRun.extraLength = 0.f;
662     }
663     else
664     {
665       lineRun.width = layout.extraBearing + layout.length + layout.extraWidth;
666       lineRun.extraLength = ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f;
667     }
668     lineRun.ascender = layout.ascender;
669     lineRun.descender = layout.descender;
670     lineRun.direction = !RTL;
671     lineRun.ellipsis = false;
672
673     // Update the actual size.
674     if( lineRun.width > layoutSize.width )
675     {
676       layoutSize.width = lineRun.width;
677     }
678
679     layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
680   }
681
682   /**
683    * @brief Updates the text layout with the last laid-out line.
684    *
685    * @param[in] layoutParameters The parameters needed to layout the text.
686    * @param[in] characterIndex The character index of the line.
687    * @param[in] glyphIndex The glyph index of the line.
688    * @param[in,out] layoutSize The text's layout size.
689    * @param[in,out] linesBuffer Pointer to the line's buffer.
690    * @param[in,out] numberOfLines The number of laid-out lines.
691    */
692   void UpdateTextLayout( const Parameters& layoutParameters,
693                          CharacterIndex characterIndex,
694                          GlyphIndex glyphIndex,
695                          Size& layoutSize,
696                          LineRun* linesBuffer,
697                          Length& numberOfLines )
698   {
699     // Need to add a new line with no characters but with height to increase the layoutSize.height
700     const GlyphInfo& glyphInfo = *( layoutParameters.glyphsBuffer + layoutParameters.totalNumberOfGlyphs - 1u );
701
702     Text::FontMetrics fontMetrics;
703     mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
704
705     LineRun& lineRun = *( linesBuffer + numberOfLines );
706     ++numberOfLines;
707
708     lineRun.glyphRun.glyphIndex = glyphIndex;
709     lineRun.glyphRun.numberOfGlyphs = 0u;
710     lineRun.characterRun.characterIndex = characterIndex;
711     lineRun.characterRun.numberOfCharacters = 0u;
712     lineRun.width = 0.f;
713     lineRun.ascender = fontMetrics.ascender;
714     lineRun.descender = fontMetrics.descender;
715     lineRun.extraLength = 0.f;
716     lineRun.alignmentOffset = 0.f;
717     lineRun.direction = !RTL;
718     lineRun.ellipsis = false;
719     lineRun.lineSpacing = mDefaultLineSpacing;
720
721     layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
722   }
723
724   /**
725    * @brief Updates the text's layout size adding the size of the previously laid-out lines.
726    *
727    * @param[in] lines The vector of lines (before the new laid-out lines are inserted).
728    * @param[in,out] layoutSize The text's layout size.
729    */
730   void UpdateLayoutSize( const Vector<LineRun>& lines,
731                          Size& layoutSize )
732   {
733     for( Vector<LineRun>::ConstIterator it = lines.Begin(),
734            endIt = lines.End();
735          it != endIt;
736          ++it )
737     {
738       const LineRun& line = *it;
739
740       if( line.width > layoutSize.width )
741       {
742         layoutSize.width = line.width;
743       }
744
745       layoutSize.height += ( line.ascender + -line.descender ) + line.lineSpacing;
746     }
747   }
748
749   /**
750    * @brief Updates the indices of the character and glyph runs of the lines before the new lines are inserted.
751    *
752    * @param[in] layoutParameters The parameters needed to layout the text.
753    * @param[in,out] lines The vector of lines (before the new laid-out lines are inserted).
754    * @param[in] characterOffset The offset to be added to the runs of characters.
755    * @param[in] glyphOffset The offset to be added to the runs of glyphs.
756    */
757   void UpdateLineIndexOffsets( const Parameters& layoutParameters,
758                                Vector<LineRun>& lines,
759                                Length characterOffset,
760                                Length glyphOffset )
761   {
762     // Update the glyph and character runs.
763     for( Vector<LineRun>::Iterator it = lines.Begin() + layoutParameters.startLineIndex,
764            endIt = lines.End();
765          it != endIt;
766          ++it )
767     {
768       LineRun& line = *it;
769
770       line.glyphRun.glyphIndex = glyphOffset;
771       line.characterRun.characterIndex = characterOffset;
772
773       glyphOffset += line.glyphRun.numberOfGlyphs;
774       characterOffset += line.characterRun.numberOfCharacters;
775     }
776   }
777
778   bool LayoutText( const Parameters& layoutParameters,
779                    Vector<Vector2>& glyphPositions,
780                    Vector<LineRun>& lines,
781                    Size& layoutSize,
782                    bool elideTextEnabled )
783   {
784     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->LayoutText\n" );
785     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height );
786
787     if( 0u == layoutParameters.numberOfGlyphs )
788     {
789       // Add an extra line if the last character is a new paragraph character and the last line doesn't have zero characters.
790       if( layoutParameters.isLastNewParagraph )
791       {
792         Length numberOfLines = lines.Count();
793         if( 0u != numberOfLines )
794         {
795           const LineRun& lastLine = *( lines.End() - 1u );
796
797           if( 0u != lastLine.characterRun.numberOfCharacters )
798           {
799             // Need to add a new line with no characters but with height to increase the layoutSize.height
800             LineRun newLine;
801             Initialize( newLine );
802             lines.PushBack( newLine );
803
804             UpdateTextLayout( layoutParameters,
805                               lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters,
806                               lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs,
807                               layoutSize,
808                               lines.Begin(),
809                               numberOfLines );
810           }
811         }
812       }
813
814       // Calculates the layout size.
815       UpdateLayoutSize( lines,
816                         layoutSize );
817
818       // Nothing else do if there are no glyphs to layout.
819       return false;
820     }
821
822     const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
823
824     // In a previous layout, an extra line with no characters may have been added if the text ended with a new paragraph character.
825     // This extra line needs to be removed.
826     if( 0u != lines.Count() )
827     {
828       Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
829
830       if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
831           ( lastGlyphPlusOne == layoutParameters.totalNumberOfGlyphs ) )
832       {
833         lines.Remove( lastLine );
834       }
835     }
836
837     // Set the first paragraph's direction.
838     CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
839
840     // Whether the layout is being updated or set from scratch.
841     const bool updateCurrentBuffer = layoutParameters.numberOfGlyphs < layoutParameters.totalNumberOfGlyphs;
842
843     Vector2* glyphPositionsBuffer = NULL;
844     Vector<Vector2> newGlyphPositions;
845
846     LineRun* linesBuffer = NULL;
847     Vector<LineRun> newLines;
848
849     // Estimate the number of lines.
850     Length linesCapacity = std::max( 1u, layoutParameters.estimatedNumberOfLines );
851     Length numberOfLines = 0u;
852
853     if( updateCurrentBuffer )
854     {
855       newGlyphPositions.Resize( layoutParameters.numberOfGlyphs );
856       glyphPositionsBuffer = newGlyphPositions.Begin();
857
858       newLines.Resize( linesCapacity );
859       linesBuffer = newLines.Begin();
860     }
861     else
862     {
863       glyphPositionsBuffer = glyphPositions.Begin();
864
865       lines.Resize( linesCapacity );
866       linesBuffer = lines.Begin();
867     }
868
869     float penY = CalculateLineOffset( lines,
870                                       layoutParameters.startLineIndex );
871
872     for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
873     {
874       CharacterDirection currentParagraphDirection = paragraphDirection;
875
876       // Get the layout for the line.
877       LineLayout layout;
878       layout.glyphIndex = index;
879       GetLineLayoutForBox( layoutParameters,
880                            layout,
881                            paragraphDirection,
882                            false );
883
884       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex );
885       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "       character index %d\n", layout.characterIndex );
886       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "      number of glyphs %d\n", layout.numberOfGlyphs );
887       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of characters %d\n", layout.numberOfCharacters );
888       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                length %f\n", layout.length );
889
890       if( 0u == layout.numberOfGlyphs )
891       {
892         // The width is too small and no characters are laid-out.
893         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n" );
894
895         lines.Resize( numberOfLines );
896         return false;
897       }
898
899       // Set the line position. Discard if ellipsis is enabled and the position exceeds the boundaries
900       // of the box.
901       penY += layout.ascender;
902
903       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  pen y %f\n", penY );
904
905       bool ellipsis = false;
906       if( elideTextEnabled )
907       {
908         // Does the ellipsis of the last line.
909         ellipsis = EllipsisLine( layoutParameters,
910                                  layout,
911                                  layoutSize,
912                                  linesBuffer,
913                                  glyphPositionsBuffer,
914                                  numberOfLines,
915                                  penY,
916                                  currentParagraphDirection );
917       }
918
919       if( ellipsis )
920       {
921         // No more lines to layout.
922         break;
923       }
924       else
925       {
926         // Whether the last line has been laid-out.
927         const bool isLastLine = index + layout.numberOfGlyphs == layoutParameters.totalNumberOfGlyphs;
928
929         if( numberOfLines == linesCapacity )
930         {
931           // Reserve more space for the next lines.
932           linesBuffer = ResizeLinesBuffer( lines,
933                                            newLines,
934                                            linesCapacity,
935                                            updateCurrentBuffer );
936         }
937
938         // Updates the current text's layout with the line's layout.
939         UpdateTextLayout( layoutParameters,
940                           layout,
941                           layoutSize,
942                           linesBuffer,
943                           index,
944                           numberOfLines,
945                           isLastLine );
946
947         const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
948
949         if( ( nextIndex == layoutParameters.totalNumberOfGlyphs ) &&
950             layoutParameters.isLastNewParagraph &&
951             ( mLayout == MULTI_LINE_BOX ) )
952         {
953           // The last character of the text is a new paragraph character.
954           // An extra line with no characters is added to increase the text's height
955           // in order to place the cursor.
956
957           if( numberOfLines == linesCapacity )
958           {
959             // Reserve more space for the next lines.
960             linesBuffer = ResizeLinesBuffer( lines,
961                                              newLines,
962                                              linesCapacity,
963                                              updateCurrentBuffer );
964           }
965
966           UpdateTextLayout( layoutParameters,
967                             layout.characterIndex + layout.numberOfCharacters,
968                             index + layout.numberOfGlyphs,
969                             layoutSize,
970                             linesBuffer,
971                             numberOfLines );
972         } // whether to add a last line.
973
974         // Sets the positions of the glyphs.
975         SetGlyphPositions( layoutParameters.glyphsBuffer + index,
976                            layout.numberOfGlyphs,
977                            layoutParameters.outlineWidth,
978                            glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
979
980         // Updates the vertical pen's position.
981         penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
982
983         // Increase the glyph index.
984         index = nextIndex;
985       } // no ellipsis
986     } // end for() traversing glyphs.
987
988     if( updateCurrentBuffer )
989     {
990       glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
991                              newGlyphPositions.Begin(),
992                              newGlyphPositions.End() );
993       glyphPositions.Resize( layoutParameters.totalNumberOfGlyphs );
994
995       newLines.Resize( numberOfLines );
996
997       // Current text's layout size adds only the newly laid-out lines.
998       // Updates the layout size with the previously laid-out lines.
999       UpdateLayoutSize( lines,
1000                         layoutSize );
1001
1002       if( 0u != newLines.Count() )
1003       {
1004         const LineRun& lastLine = *( newLines.End() - 1u );
1005
1006         const Length characterOffset = lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters;
1007         const Length glyphOffset = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
1008
1009         // Update the indices of the runs before the new laid-out lines are inserted.
1010         UpdateLineIndexOffsets( layoutParameters,
1011                                 lines,
1012                                 characterOffset,
1013                                 glyphOffset );
1014
1015         // Insert the lines.
1016         lines.Insert( lines.Begin() + layoutParameters.startLineIndex,
1017                       newLines.Begin(),
1018                       newLines.End() );
1019       }
1020     }
1021     else
1022     {
1023       lines.Resize( numberOfLines );
1024     }
1025
1026     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
1027
1028     return true;
1029   }
1030
1031   void ReLayoutRightToLeftLines( const Parameters& layoutParameters,
1032                                  CharacterIndex startIndex,
1033                                  Length numberOfCharacters,
1034                                  Vector<Vector2>& glyphPositions )
1035   {
1036     const CharacterIndex lastCharacterIndex = startIndex + numberOfCharacters;
1037
1038     // Traverses the paragraphs with right to left characters.
1039     for( LineIndex lineIndex = 0u; lineIndex < layoutParameters.numberOfBidirectionalInfoRuns; ++lineIndex )
1040     {
1041       const BidirectionalLineInfoRun& bidiLine = *( layoutParameters.lineBidirectionalInfoRunsBuffer + lineIndex );
1042
1043       if( startIndex >= bidiLine.characterRun.characterIndex + bidiLine.characterRun.numberOfCharacters )
1044       {
1045         // Do not reorder the line if it has been already reordered.
1046         continue;
1047       }
1048
1049       if( bidiLine.characterRun.characterIndex >= lastCharacterIndex )
1050       {
1051         // Do not reorder the lines after the last requested character.
1052         break;
1053       }
1054
1055       const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *bidiLine.visualToLogicalMap;
1056       const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
1057
1058       float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing - layoutParameters.outlineWidth : -layoutParameters.outlineWidth;
1059
1060       Vector2* glyphPositionsBuffer = glyphPositions.Begin();
1061
1062       // Traverses the characters of the right to left paragraph.
1063       for( CharacterIndex characterLogicalIndex = 0u;
1064            characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
1065            ++characterLogicalIndex )
1066       {
1067         // Convert the character in the logical order into the character in the visual order.
1068         const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
1069
1070         // Get the number of glyphs of the character.
1071         const Length numberOfGlyphs = *( layoutParameters.glyphsPerCharacterBuffer + characterVisualIndex );
1072
1073         for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
1074         {
1075           // Convert the character in the visual order into the glyph in the visual order.
1076           const GlyphIndex glyphIndex = *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) + index;
1077
1078           DALI_ASSERT_DEBUG( 0u <= glyphIndex && glyphIndex < layoutParameters.totalNumberOfGlyphs );
1079
1080           const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + glyphIndex );
1081           Vector2& position = *( glyphPositionsBuffer + glyphIndex );
1082
1083           position.x = penX + glyph.xBearing;
1084           penX += glyph.advance;
1085         }
1086       }
1087     }
1088   }
1089
1090   void Align( const Size& size,
1091               CharacterIndex startIndex,
1092               Length numberOfCharacters,
1093               Text::HorizontalAlignment::Type horizontalAlignment,
1094               Vector<LineRun>& lines,
1095               float& alignmentOffset )
1096   {
1097     const CharacterIndex lastCharacterPlusOne = startIndex + numberOfCharacters;
1098
1099     alignmentOffset = MAX_FLOAT;
1100     // Traverse all lines and align the glyphs.
1101     for( Vector<LineRun>::Iterator it = lines.Begin(), endIt = lines.End();
1102          it != endIt;
1103          ++it )
1104     {
1105       LineRun& line = *it;
1106
1107       if( line.characterRun.characterIndex < startIndex )
1108       {
1109         // Do not align lines which have already been aligned.
1110         continue;
1111       }
1112
1113       if( line.characterRun.characterIndex >= lastCharacterPlusOne )
1114       {
1115         // Do not align lines beyond the last laid-out character.
1116         break;
1117       }
1118
1119       // Calculate the line's alignment offset accordingly with the align option,
1120       // the box width, line length, and the paragraph's direction.
1121       CalculateHorizontalAlignment( size.width,
1122                                     horizontalAlignment,
1123                                     line );
1124
1125       // Updates the alignment offset.
1126       alignmentOffset = std::min( alignmentOffset, line.alignmentOffset );
1127     }
1128   }
1129
1130   void CalculateHorizontalAlignment( float boxWidth,
1131                                      HorizontalAlignment::Type horizontalAlignment,
1132                                      LineRun& line )
1133   {
1134     line.alignmentOffset = 0.f;
1135     const bool isRTL = RTL == line.direction;
1136     float lineLength = line.width;
1137
1138     HorizontalAlignment::Type alignment = horizontalAlignment;
1139     if( isRTL )
1140     {
1141       // Swap the alignment type if the line is right to left.
1142       switch( alignment )
1143       {
1144         case HorizontalAlignment::BEGIN:
1145         {
1146           alignment = HorizontalAlignment::END;
1147           break;
1148         }
1149         case HorizontalAlignment::CENTER:
1150         {
1151           // Nothing to do.
1152           break;
1153         }
1154         case HorizontalAlignment::END:
1155         {
1156           alignment = HorizontalAlignment::BEGIN;
1157           break;
1158         }
1159       }
1160     }
1161
1162     // Calculate the horizontal line offset.
1163     switch( alignment )
1164     {
1165       case HorizontalAlignment::BEGIN:
1166       {
1167         line.alignmentOffset = 0.f;
1168
1169         if( isRTL )
1170         {
1171           // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
1172           line.alignmentOffset -= line.extraLength;
1173         }
1174         break;
1175       }
1176       case HorizontalAlignment::CENTER:
1177       {
1178         line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
1179
1180         if( isRTL )
1181         {
1182           line.alignmentOffset -= line.extraLength;
1183         }
1184
1185         line.alignmentOffset = floorf( line.alignmentOffset ); // try to avoid pixel alignment.
1186         break;
1187       }
1188       case HorizontalAlignment::END:
1189       {
1190         if( isRTL )
1191         {
1192           lineLength += line.extraLength;
1193         }
1194
1195         line.alignmentOffset = boxWidth - lineLength;
1196         break;
1197       }
1198     }
1199   }
1200
1201   void Initialize( LineRun& line )
1202   {
1203     line.glyphRun.glyphIndex = 0u;
1204     line.glyphRun.numberOfGlyphs = 0u;
1205     line.characterRun.characterIndex = 0u;
1206     line.characterRun.numberOfCharacters = 0u;
1207     line.width = 0.f;
1208     line.ascender = 0.f;
1209     line.descender = 0.f;
1210     line.extraLength = 0.f;
1211     line.alignmentOffset = 0.f;
1212     line.direction = !RTL;
1213     line.ellipsis = false;
1214     line.lineSpacing = mDefaultLineSpacing;
1215   }
1216
1217   Type mLayout;
1218   float mCursorWidth;
1219   float mDefaultLineSpacing;
1220
1221   IntrusivePtr<Metrics> mMetrics;
1222 };
1223
1224 Engine::Engine()
1225 : mImpl( NULL )
1226 {
1227   mImpl = new Engine::Impl();
1228 }
1229
1230 Engine::~Engine()
1231 {
1232   delete mImpl;
1233 }
1234
1235 void Engine::SetMetrics( MetricsPtr& metrics )
1236 {
1237   mImpl->mMetrics = metrics;
1238 }
1239
1240 void Engine::SetLayout( Type layout )
1241 {
1242   mImpl->mLayout = layout;
1243 }
1244
1245 Engine::Type Engine::GetLayout() const
1246 {
1247   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetLayout[%d]\n", mImpl->mLayout);
1248   return mImpl->mLayout;
1249 }
1250
1251 void Engine::SetCursorWidth( int width )
1252 {
1253   mImpl->mCursorWidth = static_cast<float>( width );
1254 }
1255
1256 int Engine::GetCursorWidth() const
1257 {
1258   return static_cast<int>( mImpl->mCursorWidth );
1259 }
1260
1261 bool Engine::LayoutText( const Parameters& layoutParameters,
1262                          Vector<Vector2>& glyphPositions,
1263                          Vector<LineRun>& lines,
1264                          Size& layoutSize,
1265                          bool elideTextEnabled )
1266 {
1267   return mImpl->LayoutText( layoutParameters,
1268                             glyphPositions,
1269                             lines,
1270                             layoutSize,
1271                             elideTextEnabled );
1272 }
1273
1274 void Engine::ReLayoutRightToLeftLines( const Parameters& layoutParameters,
1275                                        CharacterIndex startIndex,
1276                                        Length numberOfCharacters,
1277                                        Vector<Vector2>& glyphPositions )
1278 {
1279   mImpl->ReLayoutRightToLeftLines( layoutParameters,
1280                                    startIndex,
1281                                    numberOfCharacters,
1282                                    glyphPositions );
1283 }
1284
1285 void Engine::Align( const Size& size,
1286                     CharacterIndex startIndex,
1287                     Length numberOfCharacters,
1288                     Text::HorizontalAlignment::Type horizontalAlignment,
1289                     Vector<LineRun>& lines,
1290                     float& alignmentOffset )
1291 {
1292   mImpl->Align( size,
1293                 startIndex,
1294                 numberOfCharacters,
1295                 horizontalAlignment,
1296                 lines,
1297                 alignmentOffset );
1298 }
1299
1300 void Engine::SetDefaultLineSpacing( float lineSpacing )
1301 {
1302   mImpl->mDefaultLineSpacing = lineSpacing;
1303 }
1304
1305 float Engine::GetDefaultLineSpacing() const
1306 {
1307   return mImpl->mDefaultLineSpacing;
1308 }
1309
1310 } // namespace Layout
1311
1312 } // namespace Text
1313
1314 } // namespace Toolkit
1315
1316 } // namespace Dali