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