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