Merge "add drag&drop support in actor level" 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     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    * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
559    *
560    * return Whether the line is ellipsized.
561    */
562   bool EllipsisLine( const Parameters& layoutParameters,
563                      const LineLayout& layout,
564                      Size& layoutSize,
565                      LineRun* linesBuffer,
566                      Vector2* glyphPositionsBuffer,
567                      Length& numberOfLines,
568                      float penY,
569                      CharacterDirection currentParagraphDirection,
570                      bool& isAutoScrollEnabled )
571   {
572     const bool ellipsis = isAutoScrollEnabled ? ( penY - layout.descender > layoutParameters.boundingBox.height ) :
573                                                 ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
574                                                   ( ( mLayout == SINGLE_LINE_BOX ) &&
575                                                   ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) );
576
577     if( ellipsis )
578     {
579       isAutoScrollEnabled = false;
580       // Do not layout more lines if ellipsis is enabled.
581
582       // The last line needs to be completely filled with characters.
583       // Part of a word may be used.
584
585       LineRun* lineRun = NULL;
586       LineLayout ellipsisLayout;
587       if( 0u != numberOfLines )
588       {
589         // Get the last line and layout it again with the 'completelyFill' flag to true.
590         lineRun = linesBuffer + ( numberOfLines - 1u );
591
592         penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
593
594         ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
595       }
596       else
597       {
598         // At least there is space reserved for one line.
599         lineRun = linesBuffer;
600
601         lineRun->glyphRun.glyphIndex = 0u;
602         ellipsisLayout.glyphIndex = 0u;
603
604         ++numberOfLines;
605       }
606
607       GetLineLayoutForBox( layoutParameters,
608                            ellipsisLayout,
609                            currentParagraphDirection,
610                            true );
611
612       lineRun->glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
613       lineRun->characterRun.characterIndex = ellipsisLayout.characterIndex;
614       lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
615       lineRun->width = ellipsisLayout.length;
616       lineRun->extraLength =  ( ellipsisLayout.wsLengthEndOfLine > 0.f ) ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.extraWidth : 0.f;
617       lineRun->ascender = ellipsisLayout.ascender;
618       lineRun->descender = ellipsisLayout.descender;
619       lineRun->direction = !RTL;
620       lineRun->ellipsis = true;
621
622       layoutSize.width = layoutParameters.boundingBox.width;
623       if( layoutSize.height < Math::MACHINE_EPSILON_1000 )
624       {
625         layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
626       }
627
628       SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
629                          ellipsisLayout.numberOfGlyphs,
630                          layoutParameters.outlineWidth,
631                          glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
632     }
633
634     return ellipsis;
635   }
636
637   /**
638    * @brief Updates the text layout with a new laid-out line.
639    *
640    * @param[in] layoutParameters The parameters needed to layout the text.
641    * @param[in] layout The line layout.
642    * @param[in,out] layoutSize The text's layout size.
643    * @param[in,out] linesBuffer Pointer to the line's buffer.
644    * @param[in] index Index to the vector of glyphs.
645    * @param[in,out] numberOfLines The number of laid-out lines.
646    * @param[in] isLastLine Whether the laid-out line is the last one.
647    */
648   void UpdateTextLayout( const Parameters& layoutParameters,
649                          const LineLayout& layout,
650                          Size& layoutSize,
651                          LineRun* linesBuffer,
652                          GlyphIndex index,
653                          Length& numberOfLines,
654                          bool isLastLine )
655   {
656     LineRun& lineRun = *( linesBuffer + numberOfLines );
657     ++numberOfLines;
658
659     lineRun.glyphRun.glyphIndex = index;
660     lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
661     lineRun.characterRun.characterIndex = layout.characterIndex;
662     lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
663     lineRun.lineSpacing = mDefaultLineSpacing;
664
665     if( isLastLine && !layoutParameters.isLastNewParagraph )
666     {
667       const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
668       if( MULTI_LINE_BOX == mLayout )
669       {
670         lineRun.width = ( width > layoutParameters.boundingBox.width ) ? layoutParameters.boundingBox.width : width;
671       }
672       else
673       {
674         lineRun.width = width;
675       }
676
677       lineRun.extraLength = 0.f;
678     }
679     else
680     {
681       lineRun.width = layout.extraBearing + layout.length + layout.extraWidth;
682       lineRun.extraLength = ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f;
683     }
684     lineRun.ascender = layout.ascender;
685     lineRun.descender = layout.descender;
686     lineRun.direction = !RTL;
687     lineRun.ellipsis = false;
688
689     // Update the actual size.
690     if( lineRun.width > layoutSize.width )
691     {
692       layoutSize.width = lineRun.width;
693     }
694
695     layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
696   }
697
698   /**
699    * @brief Updates the text layout with the last laid-out line.
700    *
701    * @param[in] layoutParameters The parameters needed to layout the text.
702    * @param[in] characterIndex The character index of the line.
703    * @param[in] glyphIndex The glyph index of the line.
704    * @param[in,out] layoutSize The text's layout size.
705    * @param[in,out] linesBuffer Pointer to the line's buffer.
706    * @param[in,out] numberOfLines The number of laid-out lines.
707    */
708   void UpdateTextLayout( const Parameters& layoutParameters,
709                          CharacterIndex characterIndex,
710                          GlyphIndex glyphIndex,
711                          Size& layoutSize,
712                          LineRun* linesBuffer,
713                          Length& numberOfLines )
714   {
715     // Need to add a new line with no characters but with height to increase the layoutSize.height
716     const GlyphInfo& glyphInfo = *( layoutParameters.glyphsBuffer + layoutParameters.totalNumberOfGlyphs - 1u );
717
718     Text::FontMetrics fontMetrics;
719     mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
720
721     LineRun& lineRun = *( linesBuffer + numberOfLines );
722     ++numberOfLines;
723
724     lineRun.glyphRun.glyphIndex = glyphIndex;
725     lineRun.glyphRun.numberOfGlyphs = 0u;
726     lineRun.characterRun.characterIndex = characterIndex;
727     lineRun.characterRun.numberOfCharacters = 0u;
728     lineRun.width = 0.f;
729     lineRun.ascender = fontMetrics.ascender;
730     lineRun.descender = fontMetrics.descender;
731     lineRun.extraLength = 0.f;
732     lineRun.alignmentOffset = 0.f;
733     lineRun.direction = !RTL;
734     lineRun.ellipsis = false;
735     lineRun.lineSpacing = mDefaultLineSpacing;
736
737     layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
738   }
739
740   /**
741    * @brief Updates the text's layout size adding the size of the previously laid-out lines.
742    *
743    * @param[in] lines The vector of lines (before the new laid-out lines are inserted).
744    * @param[in,out] layoutSize The text's layout size.
745    */
746   void UpdateLayoutSize( const Vector<LineRun>& lines,
747                          Size& layoutSize )
748   {
749     for( Vector<LineRun>::ConstIterator it = lines.Begin(),
750            endIt = lines.End();
751          it != endIt;
752          ++it )
753     {
754       const LineRun& line = *it;
755
756       if( line.width > layoutSize.width )
757       {
758         layoutSize.width = line.width;
759       }
760
761       layoutSize.height += ( line.ascender + -line.descender ) + line.lineSpacing;
762     }
763   }
764
765   /**
766    * @brief Updates the indices of the character and glyph runs of the lines before the new lines are inserted.
767    *
768    * @param[in] layoutParameters The parameters needed to layout the text.
769    * @param[in,out] lines The vector of lines (before the new laid-out lines are inserted).
770    * @param[in] characterOffset The offset to be added to the runs of characters.
771    * @param[in] glyphOffset The offset to be added to the runs of glyphs.
772    */
773   void UpdateLineIndexOffsets( const Parameters& layoutParameters,
774                                Vector<LineRun>& lines,
775                                Length characterOffset,
776                                Length glyphOffset )
777   {
778     // Update the glyph and character runs.
779     for( Vector<LineRun>::Iterator it = lines.Begin() + layoutParameters.startLineIndex,
780            endIt = lines.End();
781          it != endIt;
782          ++it )
783     {
784       LineRun& line = *it;
785
786       line.glyphRun.glyphIndex = glyphOffset;
787       line.characterRun.characterIndex = characterOffset;
788
789       glyphOffset += line.glyphRun.numberOfGlyphs;
790       characterOffset += line.characterRun.numberOfCharacters;
791     }
792   }
793
794   bool LayoutText( const Parameters& layoutParameters,
795                    Vector<Vector2>& glyphPositions,
796                    Vector<LineRun>& lines,
797                    Size& layoutSize,
798                    bool elideTextEnabled,
799                    bool& isAutoScrollEnabled )
800   {
801     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->LayoutText\n" );
802     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height );
803
804     if( 0u == layoutParameters.numberOfGlyphs )
805     {
806       // Add an extra line if the last character is a new paragraph character and the last line doesn't have zero characters.
807       if( layoutParameters.isLastNewParagraph )
808       {
809         Length numberOfLines = lines.Count();
810         if( 0u != numberOfLines )
811         {
812           const LineRun& lastLine = *( lines.End() - 1u );
813
814           if( 0u != lastLine.characterRun.numberOfCharacters )
815           {
816             // Need to add a new line with no characters but with height to increase the layoutSize.height
817             LineRun newLine;
818             Initialize( newLine );
819             lines.PushBack( newLine );
820
821             UpdateTextLayout( layoutParameters,
822                               lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters,
823                               lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs,
824                               layoutSize,
825                               lines.Begin(),
826                               numberOfLines );
827           }
828         }
829       }
830
831       // Calculates the layout size.
832       UpdateLayoutSize( lines,
833                         layoutSize );
834
835       // Nothing else do if there are no glyphs to layout.
836       return false;
837     }
838
839     const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
840
841     // In a previous layout, an extra line with no characters may have been added if the text ended with a new paragraph character.
842     // This extra line needs to be removed.
843     if( 0u != lines.Count() )
844     {
845       Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
846
847       if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
848           ( lastGlyphPlusOne == layoutParameters.totalNumberOfGlyphs ) )
849       {
850         lines.Remove( lastLine );
851       }
852     }
853
854     // Set the first paragraph's direction.
855     CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
856
857     // Whether the layout is being updated or set from scratch.
858     const bool updateCurrentBuffer = layoutParameters.numberOfGlyphs < layoutParameters.totalNumberOfGlyphs;
859
860     Vector2* glyphPositionsBuffer = NULL;
861     Vector<Vector2> newGlyphPositions;
862
863     LineRun* linesBuffer = NULL;
864     Vector<LineRun> newLines;
865
866     // Estimate the number of lines.
867     Length linesCapacity = std::max( 1u, layoutParameters.estimatedNumberOfLines );
868     Length numberOfLines = 0u;
869
870     if( updateCurrentBuffer )
871     {
872       newGlyphPositions.Resize( layoutParameters.numberOfGlyphs );
873       glyphPositionsBuffer = newGlyphPositions.Begin();
874
875       newLines.Resize( linesCapacity );
876       linesBuffer = newLines.Begin();
877     }
878     else
879     {
880       glyphPositionsBuffer = glyphPositions.Begin();
881
882       lines.Resize( linesCapacity );
883       linesBuffer = lines.Begin();
884     }
885
886     float penY = CalculateLineOffset( lines,
887                                       layoutParameters.startLineIndex );
888
889     for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
890     {
891       CharacterDirection currentParagraphDirection = paragraphDirection;
892
893       // Get the layout for the line.
894       LineLayout layout;
895       layout.glyphIndex = index;
896       GetLineLayoutForBox( layoutParameters,
897                            layout,
898                            paragraphDirection,
899                            false );
900
901       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex );
902       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "       character index %d\n", layout.characterIndex );
903       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "      number of glyphs %d\n", layout.numberOfGlyphs );
904       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of characters %d\n", layout.numberOfCharacters );
905       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                length %f\n", layout.length );
906
907       if( 0u == layout.numberOfGlyphs )
908       {
909         // The width is too small and no characters are laid-out.
910         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n" );
911
912         lines.Resize( numberOfLines );
913         return false;
914       }
915
916       // Set the line position. Discard if ellipsis is enabled and the position exceeds the boundaries
917       // of the box.
918       penY += layout.ascender;
919
920       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  pen y %f\n", penY );
921
922       bool ellipsis = false;
923       if( elideTextEnabled )
924       {
925         // Does the ellipsis of the last line.
926         ellipsis = EllipsisLine( layoutParameters,
927                                  layout,
928                                  layoutSize,
929                                  linesBuffer,
930                                  glyphPositionsBuffer,
931                                  numberOfLines,
932                                  penY,
933                                  currentParagraphDirection,
934                                  isAutoScrollEnabled );
935       }
936
937       if( ellipsis )
938       {
939         // No more lines to layout.
940         break;
941       }
942       else
943       {
944         // Whether the last line has been laid-out.
945         const bool isLastLine = index + layout.numberOfGlyphs == layoutParameters.totalNumberOfGlyphs;
946
947         if( numberOfLines == linesCapacity )
948         {
949           // Reserve more space for the next lines.
950           linesBuffer = ResizeLinesBuffer( lines,
951                                            newLines,
952                                            linesCapacity,
953                                            updateCurrentBuffer );
954         }
955
956         // Updates the current text's layout with the line's layout.
957         UpdateTextLayout( layoutParameters,
958                           layout,
959                           layoutSize,
960                           linesBuffer,
961                           index,
962                           numberOfLines,
963                           isLastLine );
964
965         const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
966
967         if( ( nextIndex == layoutParameters.totalNumberOfGlyphs ) &&
968             layoutParameters.isLastNewParagraph &&
969             ( mLayout == MULTI_LINE_BOX ) )
970         {
971           // The last character of the text is a new paragraph character.
972           // An extra line with no characters is added to increase the text's height
973           // in order to place the cursor.
974
975           if( numberOfLines == linesCapacity )
976           {
977             // Reserve more space for the next lines.
978             linesBuffer = ResizeLinesBuffer( lines,
979                                              newLines,
980                                              linesCapacity,
981                                              updateCurrentBuffer );
982           }
983
984           UpdateTextLayout( layoutParameters,
985                             layout.characterIndex + layout.numberOfCharacters,
986                             index + layout.numberOfGlyphs,
987                             layoutSize,
988                             linesBuffer,
989                             numberOfLines );
990         } // whether to add a last line.
991
992         // Sets the positions of the glyphs.
993         SetGlyphPositions( layoutParameters.glyphsBuffer + index,
994                            layout.numberOfGlyphs,
995                            layoutParameters.outlineWidth,
996                            glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
997
998         // Updates the vertical pen's position.
999         penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
1000
1001         // Increase the glyph index.
1002         index = nextIndex;
1003       } // no ellipsis
1004     } // end for() traversing glyphs.
1005
1006     if( updateCurrentBuffer )
1007     {
1008       glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
1009                              newGlyphPositions.Begin(),
1010                              newGlyphPositions.End() );
1011       glyphPositions.Resize( layoutParameters.totalNumberOfGlyphs );
1012
1013       newLines.Resize( numberOfLines );
1014
1015       // Current text's layout size adds only the newly laid-out lines.
1016       // Updates the layout size with the previously laid-out lines.
1017       UpdateLayoutSize( lines,
1018                         layoutSize );
1019
1020       if( 0u != newLines.Count() )
1021       {
1022         const LineRun& lastLine = *( newLines.End() - 1u );
1023
1024         const Length characterOffset = lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters;
1025         const Length glyphOffset = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
1026
1027         // Update the indices of the runs before the new laid-out lines are inserted.
1028         UpdateLineIndexOffsets( layoutParameters,
1029                                 lines,
1030                                 characterOffset,
1031                                 glyphOffset );
1032
1033         // Insert the lines.
1034         lines.Insert( lines.Begin() + layoutParameters.startLineIndex,
1035                       newLines.Begin(),
1036                       newLines.End() );
1037       }
1038     }
1039     else
1040     {
1041       lines.Resize( numberOfLines );
1042     }
1043
1044     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
1045
1046     return true;
1047   }
1048
1049   void ReLayoutRightToLeftLines( const Parameters& layoutParameters,
1050                                  CharacterIndex startIndex,
1051                                  Length numberOfCharacters,
1052                                  Vector<Vector2>& glyphPositions )
1053   {
1054     const CharacterIndex lastCharacterIndex = startIndex + numberOfCharacters;
1055
1056     // Traverses the paragraphs with right to left characters.
1057     for( LineIndex lineIndex = 0u; lineIndex < layoutParameters.numberOfBidirectionalInfoRuns; ++lineIndex )
1058     {
1059       const BidirectionalLineInfoRun& bidiLine = *( layoutParameters.lineBidirectionalInfoRunsBuffer + lineIndex );
1060
1061       if( startIndex >= bidiLine.characterRun.characterIndex + bidiLine.characterRun.numberOfCharacters )
1062       {
1063         // Do not reorder the line if it has been already reordered.
1064         continue;
1065       }
1066
1067       if( bidiLine.characterRun.characterIndex >= lastCharacterIndex )
1068       {
1069         // Do not reorder the lines after the last requested character.
1070         break;
1071       }
1072
1073       const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *bidiLine.visualToLogicalMap;
1074       const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
1075
1076       float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing - layoutParameters.outlineWidth : -layoutParameters.outlineWidth;
1077
1078       Vector2* glyphPositionsBuffer = glyphPositions.Begin();
1079
1080       // Traverses the characters of the right to left paragraph.
1081       for( CharacterIndex characterLogicalIndex = 0u;
1082            characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
1083            ++characterLogicalIndex )
1084       {
1085         // Convert the character in the logical order into the character in the visual order.
1086         const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
1087
1088         // Get the number of glyphs of the character.
1089         const Length numberOfGlyphs = *( layoutParameters.glyphsPerCharacterBuffer + characterVisualIndex );
1090
1091         for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
1092         {
1093           // Convert the character in the visual order into the glyph in the visual order.
1094           const GlyphIndex glyphIndex = *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) + index;
1095
1096           DALI_ASSERT_DEBUG( 0u <= glyphIndex && glyphIndex < layoutParameters.totalNumberOfGlyphs );
1097
1098           const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + glyphIndex );
1099           Vector2& position = *( glyphPositionsBuffer + glyphIndex );
1100
1101           position.x = penX + glyph.xBearing;
1102           penX += glyph.advance;
1103         }
1104       }
1105     }
1106   }
1107
1108   void Align( const Size& size,
1109               CharacterIndex startIndex,
1110               Length numberOfCharacters,
1111               Text::HorizontalAlignment::Type horizontalAlignment,
1112               Vector<LineRun>& lines,
1113               float& alignmentOffset,
1114               Dali::LayoutDirection::Type layoutDirection,
1115               bool matchSystemLanguageDirection )
1116   {
1117     const CharacterIndex lastCharacterPlusOne = startIndex + numberOfCharacters;
1118
1119     alignmentOffset = MAX_FLOAT;
1120     // Traverse all lines and align the glyphs.
1121     for( Vector<LineRun>::Iterator it = lines.Begin(), endIt = lines.End();
1122          it != endIt;
1123          ++it )
1124     {
1125       LineRun& line = *it;
1126
1127       if( line.characterRun.characterIndex < startIndex )
1128       {
1129         // Do not align lines which have already been aligned.
1130         continue;
1131       }
1132
1133       if( line.characterRun.characterIndex >= lastCharacterPlusOne )
1134       {
1135         // Do not align lines beyond the last laid-out character.
1136         break;
1137       }
1138
1139       // Calculate the line's alignment offset accordingly with the align option,
1140       // the box width, line length, and the paragraph's direction.
1141       CalculateHorizontalAlignment( size.width,
1142                                     horizontalAlignment,
1143                                     line,
1144                                     layoutDirection,
1145                                     matchSystemLanguageDirection );
1146
1147       // Updates the alignment offset.
1148       alignmentOffset = std::min( alignmentOffset, line.alignmentOffset );
1149     }
1150   }
1151
1152   void CalculateHorizontalAlignment( float boxWidth,
1153                                      HorizontalAlignment::Type horizontalAlignment,
1154                                      LineRun& line,
1155                                      Dali::LayoutDirection::Type layoutDirection,
1156                                      bool matchSystemLanguageDirection )
1157   {
1158     line.alignmentOffset = 0.f;
1159     const bool isLineRTL = RTL == line.direction;
1160     // Whether to swap the alignment.
1161     // 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.
1162     bool isLayoutRTL = isLineRTL;
1163     float lineLength = line.width;
1164
1165     // match align for system language direction
1166     if( matchSystemLanguageDirection )
1167     {
1168       // Swap the alignment type if the line is right to left.
1169       isLayoutRTL = layoutDirection == LayoutDirection::RIGHT_TO_LEFT;
1170     }
1171     // Calculate the horizontal line offset.
1172     switch( horizontalAlignment )
1173     {
1174       case HorizontalAlignment::BEGIN:
1175       {
1176         if( isLayoutRTL )
1177         {
1178           if( isLineRTL )
1179           {
1180             lineLength += line.extraLength;
1181           }
1182
1183           line.alignmentOffset = boxWidth - lineLength;
1184         }
1185         else
1186         {
1187           line.alignmentOffset = 0.f;
1188
1189           if( isLineRTL )
1190           {
1191             // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
1192             line.alignmentOffset -= line.extraLength;
1193           }
1194         }
1195         break;
1196       }
1197       case HorizontalAlignment::CENTER:
1198       {
1199         line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
1200
1201         if( isLineRTL )
1202         {
1203           line.alignmentOffset -= line.extraLength;
1204         }
1205
1206         line.alignmentOffset = floorf( line.alignmentOffset ); // try to avoid pixel alignment.
1207         break;
1208       }
1209       case HorizontalAlignment::END:
1210       {
1211         if( isLayoutRTL )
1212         {
1213           line.alignmentOffset = 0.f;
1214
1215           if( isLineRTL )
1216           {
1217             // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
1218             line.alignmentOffset -= line.extraLength;
1219           }
1220         }
1221         else
1222         {
1223           if( isLineRTL )
1224           {
1225             lineLength += line.extraLength;
1226           }
1227
1228           line.alignmentOffset = boxWidth - lineLength;
1229         }
1230         break;
1231       }
1232     }
1233   }
1234
1235   void Initialize( LineRun& line )
1236   {
1237     line.glyphRun.glyphIndex = 0u;
1238     line.glyphRun.numberOfGlyphs = 0u;
1239     line.characterRun.characterIndex = 0u;
1240     line.characterRun.numberOfCharacters = 0u;
1241     line.width = 0.f;
1242     line.ascender = 0.f;
1243     line.descender = 0.f;
1244     line.extraLength = 0.f;
1245     line.alignmentOffset = 0.f;
1246     line.direction = !RTL;
1247     line.ellipsis = false;
1248     line.lineSpacing = mDefaultLineSpacing;
1249   }
1250
1251   Type mLayout;
1252   float mCursorWidth;
1253   float mDefaultLineSpacing;
1254   float mPreviousCharacterExtraWidth;
1255
1256   IntrusivePtr<Metrics> mMetrics;
1257 };
1258
1259 Engine::Engine()
1260 : mImpl( NULL )
1261 {
1262   mImpl = new Engine::Impl();
1263 }
1264
1265 Engine::~Engine()
1266 {
1267   delete mImpl;
1268 }
1269
1270 void Engine::SetMetrics( MetricsPtr& metrics )
1271 {
1272   mImpl->mMetrics = metrics;
1273 }
1274
1275 void Engine::SetLayout( Type layout )
1276 {
1277   mImpl->mLayout = layout;
1278 }
1279
1280 Engine::Type Engine::GetLayout() const
1281 {
1282   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetLayout[%d]\n", mImpl->mLayout);
1283   return mImpl->mLayout;
1284 }
1285
1286 void Engine::SetCursorWidth( int width )
1287 {
1288   mImpl->mCursorWidth = static_cast<float>( width );
1289 }
1290
1291 int Engine::GetCursorWidth() const
1292 {
1293   return static_cast<int>( mImpl->mCursorWidth );
1294 }
1295
1296 bool Engine::LayoutText( const Parameters& layoutParameters,
1297                          Vector<Vector2>& glyphPositions,
1298                          Vector<LineRun>& lines,
1299                          Size& layoutSize,
1300                          bool elideTextEnabled,
1301                          bool& isAutoScrollEnabled )
1302 {
1303   return mImpl->LayoutText( layoutParameters,
1304                             glyphPositions,
1305                             lines,
1306                             layoutSize,
1307                             elideTextEnabled,
1308                             isAutoScrollEnabled );
1309 }
1310
1311 void Engine::ReLayoutRightToLeftLines( const Parameters& layoutParameters,
1312                                        CharacterIndex startIndex,
1313                                        Length numberOfCharacters,
1314                                        Vector<Vector2>& glyphPositions )
1315 {
1316   mImpl->ReLayoutRightToLeftLines( layoutParameters,
1317                                    startIndex,
1318                                    numberOfCharacters,
1319                                    glyphPositions );
1320 }
1321
1322 void Engine::Align( const Size& size,
1323                     CharacterIndex startIndex,
1324                     Length numberOfCharacters,
1325                     Text::HorizontalAlignment::Type horizontalAlignment,
1326                     Vector<LineRun>& lines,
1327                     float& alignmentOffset,
1328                     Dali::LayoutDirection::Type layoutDirection,
1329                     bool matchSystemLanguageDirection )
1330 {
1331   mImpl->Align( size,
1332                 startIndex,
1333                 numberOfCharacters,
1334                 horizontalAlignment,
1335                 lines,
1336                 alignmentOffset,
1337                 layoutDirection,
1338                 matchSystemLanguageDirection );
1339 }
1340
1341 void Engine::SetDefaultLineSpacing( float lineSpacing )
1342 {
1343   mImpl->mDefaultLineSpacing = lineSpacing;
1344 }
1345
1346 float Engine::GetDefaultLineSpacing() const
1347 {
1348   return mImpl->mDefaultLineSpacing;
1349 }
1350
1351 } // namespace Layout
1352
1353 } // namespace Text
1354
1355 } // namespace Toolkit
1356
1357 } // namespace Dali