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