Added UNDERLINE_HEIGHT Property to override font metrics
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.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/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <vector>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/public-api/text-abstraction/font-client.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/logical-model-impl.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/script-run.h>
35 #include <dali-toolkit/internal/text/segmentation.h>
36 #include <dali-toolkit/internal/text/shaper.h>
37 #include <dali-toolkit/internal/text/text-io.h>
38 #include <dali-toolkit/internal/text/text-view.h>
39 #include <dali-toolkit/internal/text/visual-model-impl.h>
40
41 using std::vector;
42
43 namespace
44 {
45
46 const float MAX_FLOAT = std::numeric_limits<float>::max();
47
48 enum ModifyType
49 {
50   REPLACE_TEXT, ///< Replace the entire text
51   INSERT_TEXT,  ///< Insert characters at the current cursor position
52   DELETE_TEXT   ///< Delete a character at the current cursor position
53 };
54
55 struct ModifyEvent
56 {
57   ModifyType type;
58   std::string text;
59 };
60
61 const std::string EMPTY_STRING("");
62
63 } // namespace
64
65 namespace Dali
66 {
67
68 namespace Toolkit
69 {
70
71 namespace Text
72 {
73
74 struct Controller::FontDefaults
75 {
76   FontDefaults()
77   : mDefaultPointSize(0.0f),
78     mFontId(0u)
79   {
80   }
81
82   FontId GetFontId( TextAbstraction::FontClient& fontClient )
83   {
84     if( !mFontId )
85     {
86       Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
87       mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
88     }
89
90     return mFontId;
91   }
92
93   std::string mDefaultFontFamily;
94   std::string mDefaultFontStyle;
95   float mDefaultPointSize;
96   FontId mFontId;
97 };
98
99 struct Controller::TextInput
100 {
101   // Used to queue input events until DoRelayout()
102   enum EventType
103   {
104     KEYBOARD_FOCUS_GAIN_EVENT,
105     KEYBOARD_FOCUS_LOST_EVENT,
106     CURSOR_KEY_EVENT,
107     TAP_EVENT,
108     PAN_EVENT,
109     GRAB_HANDLE_EVENT
110   };
111
112   union Param
113   {
114     int mInt;
115     unsigned int mUint;
116     float mFloat;
117   };
118
119   struct Event
120   {
121     Event( EventType eventType )
122     : type( eventType )
123     {
124       p1.mInt = 0;
125       p2.mInt = 0;
126     }
127
128     EventType type;
129     Param p1;
130     Param p2;
131     Param p3;
132   };
133
134   struct CursorInfo
135   {
136     CursorInfo()
137     : primaryPosition(),
138       secondaryPosition(),
139       lineHeight( 0.f ),
140       primaryCursorHeight( 0.f ),
141       secondaryCursorHeight( 0.f ),
142       isSecondaryCursor( false )
143     {}
144
145     ~CursorInfo()
146     {}
147
148     Vector2 primaryPosition;       ///< The primary cursor's position.
149     Vector2 secondaryPosition;     ///< The secondary cursor's position.
150     float   lineHeight;            ///< The height of the line where the cursor is placed.
151     float   primaryCursorHeight;   ///< The primary cursor's height.
152     float   secondaryCursorHeight; ///< The secondary cursor's height.
153     bool    isSecondaryCursor;     ///< Whether the secondary cursor is valid.
154   };
155
156   /**
157    * @brief Some characters can be shaped in more than one glyph.
158    * This struct is used to retrieve metrics from these group of glyphs.
159    */
160   struct GlyphMetrics
161   {
162     GlyphMetrics()
163     : fontHeight( 0.f ),
164       advance( 0.f ),
165       ascender( 0.f ),
166       xBearing( 0.f )
167     {}
168
169     ~GlyphMetrics()
170     {}
171
172     float fontHeight; ///< The font's height of that glyphs.
173     float advance;    ///< The sum of all the advances of all the glyphs.
174     float ascender;   ///< The font's ascender.
175     float xBearing;   ///< The x bearing of the first glyph.
176   };
177
178   enum State
179   {
180     INACTIVE,
181     SELECTING,
182     EDITING,
183     EDITING_WITH_POPUP
184   };
185
186   TextInput( LogicalModelPtr logicalModel,
187              VisualModelPtr visualModel,
188              DecoratorPtr decorator,
189              FontDefaults* fontDefaults,
190              TextAbstraction::FontClient& fontClient )
191   : mLogicalModel( logicalModel ),
192     mVisualModel( visualModel ),
193     mDecorator( decorator ),
194     mFontDefaults( fontDefaults ),
195     mFontClient( fontClient ),
196     mState( INACTIVE ),
197     mPrimaryCursorPosition( 0u ),
198     mSecondaryCursorPosition( 0u ),
199     mDecoratorUpdated( false ),
200     mCursorBlinkEnabled( true ),
201     mGrabHandleEnabled( true ),
202     mGrabHandlePopupEnabled( true ),
203     mSelectionEnabled( true ),
204     mHorizontalScrollingEnabled( true ),
205     mVerticalScrollingEnabled( false ),
206     mUpdateCursorPosition( false )
207   {}
208
209   /**
210    * @brief Helper to move the cursor, grab handle etc.
211    */
212   bool ProcessInputEvents( const Vector2& controlSize,
213                            const Vector2& alignmentOffset )
214   {
215     mDecoratorUpdated = false;
216
217     if( mDecorator )
218     {
219       for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
220       {
221         switch( iter->type )
222         {
223           case KEYBOARD_FOCUS_GAIN_EVENT:
224           {
225             OnKeyboardFocus( true );
226             break;
227           }
228           case KEYBOARD_FOCUS_LOST_EVENT:
229           {
230             OnKeyboardFocus( false );
231             break;
232           }
233           case CURSOR_KEY_EVENT:
234           {
235             OnCursorKeyEvent( *iter );
236             break;
237           }
238           case TAP_EVENT:
239           {
240             OnTapEvent( *iter, alignmentOffset );
241             break;
242           }
243           case PAN_EVENT:
244           {
245             OnPanEvent( *iter, controlSize, alignmentOffset );
246             break;
247           }
248           case GRAB_HANDLE_EVENT:
249           {
250             OnGrabHandleEvent( *iter );
251             break;
252           }
253         }
254       }
255     }
256
257     // The cursor must also be repositioned after inserts into the model
258     if( mUpdateCursorPosition )
259     {
260       UpdateCursorPosition();
261       mUpdateCursorPosition = false;
262     }
263
264     mEventQueue.clear();
265
266     return mDecoratorUpdated;
267   }
268
269   void OnKeyboardFocus( bool hasFocus )
270   {
271     if( !hasFocus )
272     {
273       ChangeState( INACTIVE );
274     }
275     else
276     {
277       ChangeState( EDITING );
278     }
279   }
280
281   void OnCursorKeyEvent( const Event& event )
282   {
283     int keyCode = event.p1.mInt;
284
285     if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
286     {
287       if( mPrimaryCursorPosition > 0u )
288       {
289         mPrimaryCursorPosition = CalculateNewCursorIndex( mPrimaryCursorPosition - 1u );
290       }
291     }
292     else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
293     {
294       if( mLogicalModel->GetNumberOfCharacters() > mPrimaryCursorPosition )
295       {
296         mPrimaryCursorPosition = CalculateNewCursorIndex( mPrimaryCursorPosition );
297       }
298     }
299     else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
300     {
301       // TODO
302     }
303     else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
304     {
305       // TODO
306     }
307
308     UpdateCursorPosition();
309   }
310
311   void HandleCursorKey( int keyCode )
312   {
313     // TODO
314   }
315
316   void OnTapEvent( const Event& event,
317                    const Vector2& alignmentOffset  )
318   {
319     unsigned int tapCount = event.p1.mUint;
320
321     if( 1u == tapCount )
322     {
323       ChangeState( EDITING );
324
325       float xPosition = event.p2.mFloat - alignmentOffset.x;
326       float yPosition = event.p3.mFloat - alignmentOffset.y;
327
328       mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
329                                                       yPosition );
330
331       UpdateCursorPosition();
332     }
333     else if( mSelectionEnabled &&
334              2u == tapCount )
335     {
336       ChangeState( SELECTING );
337
338       RepositionSelectionHandles( event.p2.mFloat, event.p3.mFloat );
339     }
340  }
341
342   void OnPanEvent( const Event& event,
343                    const Vector2& controlSize,
344                    const Vector2& alignmentOffset )
345   {
346     int state = event.p1.mInt;
347
348     if( Gesture::Started    == state ||
349         Gesture::Continuing == state )
350     {
351       const Vector2& actualSize = mVisualModel->GetActualSize();
352
353       if( mHorizontalScrollingEnabled )
354       {
355         const float displacementX = event.p2.mFloat;
356         mScrollPosition.x += displacementX;
357
358         // Clamp between -space & 0 (and the text alignment).
359         const float contentWidth = actualSize.width;
360         if( contentWidth > controlSize.width )
361         {
362           const float space = ( contentWidth - controlSize.width ) + alignmentOffset.x;
363           mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x;
364           mScrollPosition.x = ( mScrollPosition.x > -alignmentOffset.x ) ? -alignmentOffset.x : mScrollPosition.x;
365
366           mDecoratorUpdated = true;
367         }
368         else
369         {
370           mScrollPosition.x = 0.f;
371         }
372       }
373
374       if( mVerticalScrollingEnabled )
375       {
376         const float displacementY = event.p3.mFloat;
377         mScrollPosition.y += displacementY;
378
379         // Clamp between -space & 0 (and the text alignment).
380         if( actualSize.height > controlSize.height )
381         {
382           const float space = ( actualSize.height - controlSize.height ) + alignmentOffset.y;
383           mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y;
384           mScrollPosition.y = ( mScrollPosition.y > -alignmentOffset.y ) ? -alignmentOffset.y : mScrollPosition.y;
385
386           mDecoratorUpdated = true;
387         }
388         else
389         {
390           mScrollPosition.y = 0.f;
391         }
392       }
393     }
394   }
395
396   void OnGrabHandleEvent( const Event& event )
397   {
398     unsigned int state = event.p1.mUint;
399
400     if( GRAB_HANDLE_PRESSED == state )
401     {
402       float xPosition = event.p2.mFloat + mScrollPosition.x;
403       float yPosition = event.p3.mFloat + mScrollPosition.y;
404
405       mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
406                                                       yPosition );
407
408       UpdateCursorPosition();
409
410       //mDecorator->HidePopup();
411       ChangeState ( EDITING );
412     }
413     else if ( mGrabHandlePopupEnabled &&
414               GRAB_HANDLE_RELEASED == state )
415     {
416       //mDecorator->ShowPopup();
417       ChangeState ( EDITING_WITH_POPUP );
418       mDecoratorUpdated = true;
419     }
420   }
421
422   void RepositionSelectionHandles( float visualX, float visualY )
423   {
424     // TODO - Find which word was selected
425
426     const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
427     const Vector<Vector2>::SizeType glyphCount = glyphs.Count();
428
429     const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
430     const Vector<Vector2>::SizeType positionCount = positions.Count();
431
432     // Guard against glyphs which did not fit inside the layout
433     const Vector<Vector2>::SizeType count = (positionCount < glyphCount) ? positionCount : glyphCount;
434
435     if( count )
436     {
437       float primaryX   = positions[0].x;
438       float secondaryX = positions[count-1].x + glyphs[count-1].width;
439
440       // TODO - multi-line selection
441       const Vector<LineRun>& lines = mVisualModel->mLines;
442       float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
443
444       mDecorator->SetPosition( PRIMARY_SELECTION_HANDLE,   primaryX,   0.0f, height );
445       mDecorator->SetPosition( SECONDARY_SELECTION_HANDLE, secondaryX, 0.0f, height );
446
447       mDecorator->ClearHighlights();
448       mDecorator->AddHighlight( primaryX, 0.0f, secondaryX, height );
449     }
450   }
451
452   void ChangeState( State newState )
453   {
454     if( mState != newState )
455     {
456       mState = newState;
457
458       if( INACTIVE == mState )
459       {
460         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
461         mDecorator->StopCursorBlink();
462         mDecorator->SetGrabHandleActive( false );
463         mDecorator->SetSelectionActive( false );
464         mDecorator->SetPopupActive( false );
465         mDecoratorUpdated = true;
466       }
467       else if ( SELECTING == mState )
468       {
469         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
470         mDecorator->StopCursorBlink();
471         mDecorator->SetGrabHandleActive( false );
472         mDecorator->SetSelectionActive( true );
473         mDecoratorUpdated = true;
474       }
475       else if( EDITING == mState )
476       {
477         mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
478         if( mCursorBlinkEnabled )
479         {
480           mDecorator->StartCursorBlink();
481         }
482         if( mGrabHandleEnabled )
483         {
484           mDecorator->SetGrabHandleActive( true );
485         }
486         if( mGrabHandlePopupEnabled )
487         {
488           mDecorator->SetPopupActive( false );
489         }
490         mDecorator->SetSelectionActive( false );
491         mDecoratorUpdated = true;
492       }
493       else if( EDITING_WITH_POPUP == mState )
494       {
495         mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
496         if( mCursorBlinkEnabled )
497         {
498           mDecorator->StartCursorBlink();
499         }
500         if( mGrabHandleEnabled )
501         {
502           mDecorator->SetGrabHandleActive( true );
503         }
504         if( mGrabHandlePopupEnabled )
505         {
506           mDecorator->SetPopupActive( true );
507         }
508         mDecorator->SetSelectionActive( false );
509         mDecoratorUpdated = true;
510       }
511     }
512   }
513
514   LineIndex GetClosestLine( float y ) const
515   {
516     float totalHeight = 0.f;
517     LineIndex lineIndex = 0u;
518
519     const Vector<LineRun>& lines = mVisualModel->mLines;
520     for( LineIndex endLine = lines.Count();
521          lineIndex < endLine;
522          ++lineIndex )
523     {
524       const LineRun& lineRun = lines[lineIndex];
525       totalHeight += lineRun.ascender + -lineRun.descender;
526       if( y < totalHeight )
527       {
528         return lineIndex;
529       }
530     }
531
532     return lineIndex-1;
533   }
534
535   /**
536    * @brief Retrieves the cursor's logical position for a given touch point x,y
537    *
538    * @param[in] visualX The touch point x.
539    * @param[in] visualY The touch point y.
540    *
541    * @return The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
542    */
543   CharacterIndex GetClosestCursorIndex( float visualX,
544                                         float visualY ) const
545   {
546     CharacterIndex logicalIndex = 0u;
547
548     const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
549     const Length numberOfLines  = mVisualModel->mLines.Count();
550     if( 0 == numberOfGlyphs ||
551         0 == numberOfLines )
552     {
553       return logicalIndex;
554     }
555
556     // Transform to visual model coords
557     visualX -= mScrollPosition.x;
558     visualY -= mScrollPosition.y;
559
560     // Find which line is closest
561     const LineIndex lineIndex = GetClosestLine( visualY );
562     const LineRun& line = mVisualModel->mLines[lineIndex];
563
564     // Get the positions of the glyphs.
565     const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
566     const Vector2* const positionsBuffer = positions.Begin();
567
568     // Get the visual to logical conversion tables.
569     const CharacterIndex* const visualToLogicalBuffer = ( 0u != mLogicalModel->mVisualToLogicalMap.Count() ) ? mLogicalModel->mVisualToLogicalMap.Begin() : NULL;
570     const CharacterIndex* const visualToLogicalCursorBuffer = mLogicalModel->mVisualToLogicalCursorMap.Begin();
571
572     // Get the character to glyph conversion table.
573     const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
574
575     // Get the glyphs per character table.
576     const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
577
578     // If the vector is void, there is no right to left characters.
579     const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
580
581     const CharacterIndex startCharacter = line.characterRun.characterIndex;
582     const CharacterIndex endCharacter   = line.characterRun.characterIndex + line.characterRun.numberOfCharacters;
583     DALI_ASSERT_DEBUG( endCharacter <= mLogicalModel->mText.Count() && "Invalid line info" );
584
585     // Whether there is a hit on a glyph.
586     bool matched = false;
587
588     // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
589     CharacterIndex visualIndex = startCharacter;
590     for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
591     {
592       // The character in logical order.
593       const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
594
595       // The first glyph for that character in logical order.
596       const GlyphIndex glyphLogicalOrderIndex = *( charactersToGlyphBuffer + characterLogicalOrderIndex );
597
598       // The number of glyphs for that character
599       const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
600
601       // Get the metrics for the group of glyphs.
602       GlyphMetrics glyphMetrics;
603       GetGlyphsMetrics( glyphLogicalOrderIndex,
604                         numberOfGlyphs,
605                         glyphMetrics );
606
607       const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
608
609       const float glyphX = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
610
611       if( visualX < glyphX )
612       {
613         matched = true;
614         break;
615       }
616     }
617
618     // Return the logical position of the cursor in characters.
619
620     if( !matched )
621     {
622       visualIndex = endCharacter;
623     }
624
625     return hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
626   }
627
628   /**
629    * @brief Calculates the cursor's position for a given character index in the logical order.
630    *
631    * It retrieves as well the line's height and the cursor's height and
632    * if there is a valid alternative cursor, its position and height.
633    *
634    * @param[in] logical The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
635    * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
636    */
637   void GetCursorPosition( CharacterIndex logical,
638                           CursorInfo& cursorInfo ) const
639   {
640     // TODO: Check for multiline with \n, etc...
641
642     // Check if the logical position is the first or the last one of the text.
643     const bool isFirstPosition = 0u == logical;
644     const bool isLastPosition = mLogicalModel->GetNumberOfCharacters() == logical;
645
646     if( isFirstPosition && isLastPosition )
647     {
648       // There is zero characters. Get the default font.
649
650       FontId defaultFontId = 0u;
651       if( NULL == mFontDefaults )
652       {
653         defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
654                                                EMPTY_STRING );
655       }
656       else
657       {
658         defaultFontId = mFontDefaults->GetFontId( mFontClient );
659       }
660
661       Text::FontMetrics fontMetrics;
662       mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
663
664       cursorInfo.lineHeight = fontMetrics.ascender - fontMetrics.descender;
665       cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
666
667       cursorInfo.primaryPosition.x = 0.f;
668       cursorInfo.primaryPosition.y = 0.f;
669
670       // Nothing else to do.
671       return;
672     }
673
674     // Get the previous logical index.
675     const CharacterIndex previousLogical = isFirstPosition ? 0u : logical - 1u;
676
677     // Decrease the logical index if it's the last one.
678     if( isLastPosition )
679     {
680       --logical;
681     }
682
683     // Get the direction of the character and the previous one.
684     const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
685
686     CharacterDirection isCurrentRightToLeft = false;
687     CharacterDirection isPreviousRightToLeft = false;
688     if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
689     {
690       isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + logical );
691       isPreviousRightToLeft = *( modelCharacterDirectionsBuffer + previousLogical );
692     }
693
694     // Get the line where the character is laid-out.
695     const LineRun* modelLines = mVisualModel->mLines.Begin();
696
697     const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( logical );
698     const LineRun& line = *( modelLines + lineIndex );
699
700     // Get the paragraph's direction.
701     const CharacterDirection isRightToLeftParagraph = line.direction;
702
703     // Check whether there is an alternative position:
704
705     cursorInfo.isSecondaryCursor = ( isCurrentRightToLeft != isPreviousRightToLeft ) ||
706                                    ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
707
708     // Set the line height.
709     cursorInfo.lineHeight = line.ascender + -line.descender;
710
711     // Convert the cursor position into the glyph position.
712     CharacterIndex characterIndex = logical;
713     if( cursorInfo.isSecondaryCursor &&
714         ( isRightToLeftParagraph != isCurrentRightToLeft ) )
715     {
716       characterIndex = previousLogical;
717     }
718
719     const GlyphIndex currentGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
720     const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
721     const Length numberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() +currentGlyphIndex );
722
723     // Get the metrics for the group of glyphs.
724     GlyphMetrics glyphMetrics;
725     GetGlyphsMetrics( currentGlyphIndex,
726                       numberOfGlyphs,
727                       glyphMetrics );
728
729     float interGlyphAdvance = 0.f;
730     if( !isLastPosition &&
731         ( numberOfCharacters > 1u ) )
732     {
733       const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + currentGlyphIndex );
734       interGlyphAdvance = static_cast<float>( characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( numberOfCharacters );
735     }
736
737     // Get the glyph position and x bearing.
738     const Vector2& currentPosition = *( mVisualModel->mGlyphPositions.Begin() + currentGlyphIndex );
739
740     // Set the cursor's height.
741     cursorInfo.primaryCursorHeight = glyphMetrics.fontHeight;
742
743     // Set the position.
744     cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + currentPosition.x + ( isCurrentRightToLeft ? glyphMetrics.advance : interGlyphAdvance );
745     cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
746
747     if( isLastPosition )
748     {
749       // The position of the cursor after the last character needs special
750       // care depending on its direction and the direction of the paragraph.
751
752       if( cursorInfo.isSecondaryCursor )
753       {
754         // Need to find the first character after the last character with the paragraph's direction.
755         // i.e l0 l1 l2 r0 r1 should find r0.
756
757         // TODO: check for more than one line!
758         characterIndex = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
759         characterIndex = mLogicalModel->GetLogicalCharacterIndex( characterIndex );
760
761         const GlyphIndex glyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
762         const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
763
764         const Vector2& position = *( mVisualModel->mGlyphPositions.Begin() + glyphIndex );
765
766         // Get the metrics for the group of glyphs.
767         GlyphMetrics glyphMetrics;
768         GetGlyphsMetrics( glyphIndex,
769                           numberOfGlyphs,
770                           glyphMetrics );
771
772         cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + position.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
773
774         cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
775       }
776       else
777       {
778         if( !isCurrentRightToLeft )
779         {
780           cursorInfo.primaryPosition.x += glyphMetrics.advance;
781         }
782         else
783         {
784           cursorInfo.primaryPosition.x -= glyphMetrics.advance;
785         }
786       }
787     }
788
789     // Set the alternative cursor position.
790     if( cursorInfo.isSecondaryCursor )
791     {
792       // Convert the cursor position into the glyph position.
793       const CharacterIndex previousCharacterIndex = ( ( isRightToLeftParagraph != isCurrentRightToLeft ) ? logical : previousLogical );
794       const GlyphIndex previousGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + previousCharacterIndex );
795       const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + previousCharacterIndex );
796
797       // Get the glyph position.
798       const Vector2& previousPosition = *( mVisualModel->mGlyphPositions.Begin() + previousGlyphIndex );
799
800       // Get the metrics for the group of glyphs.
801       GlyphMetrics glyphMetrics;
802       GetGlyphsMetrics( previousGlyphIndex,
803                         numberOfGlyphs,
804                         glyphMetrics );
805
806       // Set the cursor position and height.
807       cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + previousPosition.x + ( ( ( isLastPosition && !isCurrentRightToLeft ) ||
808                                                                                          ( !isLastPosition && isCurrentRightToLeft )    ) ? glyphMetrics.advance : 0.f );
809
810       cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
811
812       cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
813
814       // Update the primary cursor height as well.
815       cursorInfo.primaryCursorHeight *= 0.5f;
816     }
817   }
818
819   /**
820    * @brief Get some glyph's metrics of a group of glyphs formed as a result of shaping one character.
821    *
822    * @param[in] glyphIndex The index to the first glyph.
823    * @param[in] numberOfGlyphs The number of glyphs.
824    * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
825    */
826   void GetGlyphsMetrics( GlyphIndex glyphIndex,
827                          Length numberOfGlyphs,
828                          GlyphMetrics& glyphMetrics ) const
829   {
830     const GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
831
832     const GlyphInfo& firstGlyph = *( glyphsBuffer + glyphIndex );
833
834     Text::FontMetrics fontMetrics;
835     mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
836
837     glyphMetrics.fontHeight = fontMetrics.height;
838     glyphMetrics.advance = firstGlyph.advance;
839     glyphMetrics.ascender = fontMetrics.ascender;
840     glyphMetrics.xBearing = firstGlyph.xBearing;
841
842     for( unsigned int i = 1u; i < numberOfGlyphs; ++i )
843     {
844       const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i );
845
846       glyphMetrics.advance += glyphInfo.advance;
847     }
848   }
849
850   /**
851    * @brief Calculates the new cursor index.
852    *
853    * It takes into account that in some scripts multiple characters can form a glyph and all of them
854    * need to be jumped with one key event.
855    *
856    * @param[in] index The initial new index.
857    *
858    * @return The new cursor index.
859    */
860   CharacterIndex CalculateNewCursorIndex( CharacterIndex index ) const
861   {
862     CharacterIndex cursorIndex = mPrimaryCursorPosition;
863
864     const Script script = mLogicalModel->GetScript( index );
865     const GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
866     const Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
867
868     Length numberOfCharacters = 0u;
869     if( TextAbstraction::LATIN == script )
870     {
871       // Prevents to jump the whole Latin ligatures like fi, ff, ...
872       numberOfCharacters = 1u;
873     }
874     else
875     {
876       GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
877       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
878
879       while( 0u == numberOfCharacters )
880       {
881         numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
882         ++glyphIndex;
883       }
884     }
885
886     if( index < mPrimaryCursorPosition )
887     {
888       cursorIndex -= numberOfCharacters;
889     }
890     else
891     {
892       cursorIndex += numberOfCharacters;
893     }
894
895     return cursorIndex;
896   }
897
898   void UpdateCursorPosition()
899   {
900     CursorInfo cursorInfo;
901
902     GetCursorPosition( mPrimaryCursorPosition,
903                        cursorInfo );
904
905     mDecorator->SetPosition( PRIMARY_CURSOR,
906                              cursorInfo.primaryPosition.x,
907                              cursorInfo.primaryPosition.y,
908                              cursorInfo.primaryCursorHeight,
909                              cursorInfo.lineHeight );
910
911     if( cursorInfo.isSecondaryCursor )
912     {
913       mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
914       mDecorator->SetPosition( SECONDARY_CURSOR,
915                                cursorInfo.secondaryPosition.x,
916                                cursorInfo.secondaryPosition.y,
917                                cursorInfo.secondaryCursorHeight,
918                                cursorInfo.lineHeight );
919     }
920     else
921     {
922       mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
923     }
924
925     mUpdateCursorPosition = false;
926     mDecoratorUpdated = true;
927   }
928
929   LogicalModelPtr              mLogicalModel;
930   VisualModelPtr               mVisualModel;
931   DecoratorPtr                 mDecorator;
932   FontDefaults*                mFontDefaults;
933   TextAbstraction::FontClient& mFontClient;
934   std::string                  mPlaceholderText;
935
936   /**
937    * This is used to delay handling events until after the model has been updated.
938    * The number of updates to the model is minimized to improve performance.
939    */
940   vector<Event> mEventQueue; ///< The queue of touch events etc.
941
942   State mState; ///< Selection mode, edit mode etc.
943
944   CharacterIndex mPrimaryCursorPosition;   ///< Index into logical model for primary cursor
945   CharacterIndex mSecondaryCursorPosition; ///< Index into logical model for secondary cursor
946
947   /**
948    * 0,0 means that the top-left corner of the layout matches the top-left corner of the UI control.
949    * Typically this will have a negative value with scrolling occurs.
950    */
951   Vector2 mScrollPosition; ///< The text is offset by this position when scrolling.
952
953   bool mDecoratorUpdated           : 1; ///< True if the decorator was updated during event processing
954   bool mCursorBlinkEnabled         : 1; ///< True if cursor should blink when active
955   bool mGrabHandleEnabled          : 1; ///< True if grab handle is enabled
956   bool mGrabHandlePopupEnabled     : 1; ///< True if the grab handle popu-up should be shown
957   bool mSelectionEnabled           : 1; ///< True if selection handles, highlight etc. are enabled
958   bool mHorizontalScrollingEnabled : 1; ///< True if horizontal scrolling is enabled
959   bool mVerticalScrollingEnabled   : 1; ///< True if vertical scrolling is enabled
960   bool mUpdateCursorPosition       : 1; ///< True if the visual position of the cursor must be recalculated
961 };
962
963 struct Controller::Impl
964 {
965   Impl( ControlInterface& controlInterface )
966   : mControlInterface( controlInterface ),
967     mLogicalModel(),
968     mVisualModel(),
969     mFontDefaults( NULL ),
970     mTextInput( NULL ),
971     mFontClient(),
972     mView(),
973     mLayoutEngine(),
974     mModifyEvents(),
975     mControlSize(),
976     mAlignmentOffset(),
977     mOperationsPending( NO_OPERATION ),
978     mRecalculateNaturalSize( true )
979   {
980     mLogicalModel = LogicalModel::New();
981     mVisualModel  = VisualModel::New();
982
983     mFontClient = TextAbstraction::FontClient::Get();
984
985     mView.SetVisualModel( mVisualModel );
986
987     // Set the text properties to default
988     mVisualModel->SetTextColor( Color::WHITE );
989     mVisualModel->SetShadowOffset( Vector2::ZERO );
990     mVisualModel->SetShadowColor( Vector4::ZERO );
991     mVisualModel->SetUnderlineEnabled( false );
992     mVisualModel->SetUnderlineHeight( 0.0f );
993   }
994
995   ~Impl()
996   {
997     delete mTextInput;
998   }
999
1000   ControlInterface& mControlInterface;     ///< Reference to the text controller.
1001   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
1002   VisualModelPtr  mVisualModel;            ///< Pointer to the visual model.
1003   FontDefaults* mFontDefaults;             ///< Avoid allocating this when the user does not specify a font.
1004   Controller::TextInput* mTextInput;       ///< Avoid allocating everything for text input until EnableTextInput().
1005   TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
1006   View mView;                              ///< The view interface to the rendering back-end.
1007   LayoutEngine mLayoutEngine;              ///< The layout engine.
1008   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
1009   Size mControlSize;                       ///< The size of the control.
1010   Vector2 mAlignmentOffset;                ///< Vertical and horizontal offset of the whole text inside the control due to alignment.
1011   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
1012   bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
1013 };
1014
1015 ControllerPtr Controller::New( ControlInterface& controlInterface )
1016 {
1017   return ControllerPtr( new Controller( controlInterface ) );
1018 }
1019
1020 void Controller::SetText( const std::string& text )
1021 {
1022   // Cancel previously queued inserts etc.
1023   mImpl->mModifyEvents.clear();
1024
1025   // Keep until size negotiation
1026   ModifyEvent event;
1027   event.type = REPLACE_TEXT;
1028   event.text = text;
1029   mImpl->mModifyEvents.push_back( event );
1030
1031   if( mImpl->mTextInput )
1032   {
1033     // Cancel previously queued events
1034     mImpl->mTextInput->mEventQueue.clear();
1035
1036     // TODO - Hide selection decorations
1037   }
1038 }
1039
1040 void Controller::GetText( std::string& text ) const
1041 {
1042   if( !mImpl->mModifyEvents.empty() &&
1043        REPLACE_TEXT == mImpl->mModifyEvents[0].type )
1044   {
1045     text = mImpl->mModifyEvents[0].text;
1046   }
1047   else
1048   {
1049     // TODO - Convert from UTF-32
1050   }
1051 }
1052
1053 void Controller::SetPlaceholderText( const std::string& text )
1054 {
1055   if( !mImpl->mTextInput )
1056   {
1057     mImpl->mTextInput->mPlaceholderText = text;
1058   }
1059 }
1060
1061 void Controller::GetPlaceholderText( std::string& text ) const
1062 {
1063   if( !mImpl->mTextInput )
1064   {
1065     text = mImpl->mTextInput->mPlaceholderText;
1066   }
1067 }
1068
1069 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
1070 {
1071   if( !mImpl->mFontDefaults )
1072   {
1073     mImpl->mFontDefaults = new Controller::FontDefaults();
1074   }
1075
1076   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
1077   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1078   mImpl->mOperationsPending = ALL_OPERATIONS;
1079   mImpl->mRecalculateNaturalSize = true;
1080
1081   // Clear the font-specific data
1082   mImpl->mLogicalModel->mFontRuns.Clear();
1083   mImpl->mVisualModel->mGlyphs.Clear();
1084   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1085   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1086   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1087   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1088   mImpl->mVisualModel->mGlyphPositions.Clear();
1089   mImpl->mVisualModel->mLines.Clear();
1090   mImpl->mVisualModel->ClearCaches();
1091
1092   RequestRelayout();
1093 }
1094
1095 const std::string& Controller::GetDefaultFontFamily() const
1096 {
1097   if( mImpl->mFontDefaults )
1098   {
1099     return mImpl->mFontDefaults->mDefaultFontFamily;
1100   }
1101
1102   return EMPTY_STRING;
1103 }
1104
1105 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
1106 {
1107   if( !mImpl->mFontDefaults )
1108   {
1109     mImpl->mFontDefaults = new Controller::FontDefaults();
1110   }
1111
1112   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
1113   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1114   mImpl->mOperationsPending = ALL_OPERATIONS;
1115   mImpl->mRecalculateNaturalSize = true;
1116
1117   // Clear the font-specific data
1118   mImpl->mLogicalModel->mFontRuns.Clear();
1119   mImpl->mVisualModel->mGlyphs.Clear();
1120   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1121   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1122   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1123   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1124   mImpl->mVisualModel->mGlyphPositions.Clear();
1125   mImpl->mVisualModel->mLines.Clear();
1126   mImpl->mVisualModel->ClearCaches();
1127
1128   RequestRelayout();
1129 }
1130
1131 const std::string& Controller::GetDefaultFontStyle() const
1132 {
1133   if( mImpl->mFontDefaults )
1134   {
1135     return mImpl->mFontDefaults->mDefaultFontStyle;
1136   }
1137
1138   return EMPTY_STRING;
1139 }
1140
1141 void Controller::SetDefaultPointSize( float pointSize )
1142 {
1143   if( !mImpl->mFontDefaults )
1144   {
1145     mImpl->mFontDefaults = new Controller::FontDefaults();
1146   }
1147
1148   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
1149   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1150   mImpl->mOperationsPending = ALL_OPERATIONS;
1151   mImpl->mRecalculateNaturalSize = true;
1152
1153   // Clear the font-specific data
1154   mImpl->mLogicalModel->mFontRuns.Clear();
1155   mImpl->mVisualModel->mGlyphs.Clear();
1156   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1157   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1158   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1159   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1160   mImpl->mVisualModel->mGlyphPositions.Clear();
1161   mImpl->mVisualModel->mLines.Clear();
1162   mImpl->mVisualModel->ClearCaches();
1163
1164   RequestRelayout();
1165 }
1166
1167 float Controller::GetDefaultPointSize() const
1168 {
1169   if( mImpl->mFontDefaults )
1170   {
1171     return mImpl->mFontDefaults->mDefaultPointSize;
1172   }
1173
1174   return 0.0f;
1175 }
1176
1177 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters ) const
1178 {
1179   if( mImpl->mFontDefaults )
1180   {
1181     FontRun fontRun;
1182     fontRun.characterRun.characterIndex = 0;
1183     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
1184     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
1185     fontRun.isDefault = true;
1186
1187     fonts.PushBack( fontRun );
1188   }
1189 }
1190
1191 const Vector4& Controller::GetTextColor() const
1192 {
1193   return mImpl->mVisualModel->GetTextColor();
1194 }
1195
1196 const Vector2& Controller::GetShadowOffset() const
1197 {
1198   return mImpl->mVisualModel->GetShadowOffset();
1199 }
1200
1201 const Vector4& Controller::GetShadowColor() const
1202 {
1203   return mImpl->mVisualModel->GetShadowColor();
1204 }
1205
1206 const Vector4& Controller::GetUnderlineColor() const
1207 {
1208   return mImpl->mVisualModel->GetUnderlineColor();
1209 }
1210
1211 bool Controller::IsUnderlineEnabled() const
1212 {
1213   return mImpl->mVisualModel->IsUnderlineEnabled();
1214 }
1215
1216 float Controller::GetUnderlineHeight() const
1217 {
1218   return mImpl->mVisualModel->GetUnderlineHeight();
1219 }
1220
1221 void Controller::SetTextColor( const Vector4& textColor )
1222 {
1223   mImpl->mVisualModel->SetTextColor( textColor );
1224 }
1225
1226 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1227 {
1228   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
1229 }
1230
1231 void Controller::SetShadowColor( const Vector4& shadowColor )
1232 {
1233   mImpl->mVisualModel->SetShadowColor( shadowColor );
1234 }
1235
1236 void Controller::SetUnderlineColor( const Vector4& color )
1237 {
1238   mImpl->mVisualModel->SetUnderlineColor( color );
1239 }
1240
1241 void Controller::SetUnderlineEnabled( bool enabled )
1242 {
1243   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
1244 }
1245
1246 void Controller::SetUnderlineHeight( float height )
1247 {
1248   mImpl->mVisualModel->SetUnderlineHeight( height );
1249 }
1250
1251 void Controller::EnableTextInput( DecoratorPtr decorator )
1252 {
1253   if( !mImpl->mTextInput )
1254   {
1255     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel,
1256                                        mImpl->mVisualModel,
1257                                        decorator,
1258                                        mImpl->mFontDefaults,
1259                                        mImpl->mFontClient );
1260   }
1261 }
1262
1263 void Controller::SetEnableCursorBlink( bool enable )
1264 {
1265   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
1266
1267   if( mImpl->mTextInput )
1268   {
1269     mImpl->mTextInput->mCursorBlinkEnabled = enable;
1270
1271     if( !enable &&
1272         mImpl->mTextInput->mDecorator )
1273     {
1274       mImpl->mTextInput->mDecorator->StopCursorBlink();
1275     }
1276   }
1277 }
1278
1279 bool Controller::GetEnableCursorBlink() const
1280 {
1281   if( mImpl->mTextInput )
1282   {
1283     return mImpl->mTextInput->mCursorBlinkEnabled;
1284   }
1285
1286   return false;
1287 }
1288
1289 const Vector2& Controller::GetScrollPosition() const
1290 {
1291   if( mImpl->mTextInput )
1292   {
1293     return mImpl->mTextInput->mScrollPosition;
1294   }
1295
1296   return Vector2::ZERO;
1297 }
1298
1299 const Vector2& Controller::GetAlignmentOffset() const
1300 {
1301   return mImpl->mAlignmentOffset;
1302 }
1303
1304 Vector3 Controller::GetNaturalSize()
1305 {
1306   Vector3 naturalSize;
1307
1308   // Make sure the model is up-to-date before layouting
1309   ProcessModifyEvents();
1310
1311   if( mImpl->mRecalculateNaturalSize )
1312   {
1313     // Operations that can be done only once until the text changes.
1314     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1315                                                                            GET_SCRIPTS       |
1316                                                                            VALIDATE_FONTS    |
1317                                                                            GET_LINE_BREAKS   |
1318                                                                            GET_WORD_BREAKS   |
1319                                                                            BIDI_INFO         |
1320                                                                            SHAPE_TEXT        |
1321                                                                            GET_GLYPH_METRICS );
1322     // Make sure the model is up-to-date before layouting
1323     UpdateModel( onlyOnceOperations );
1324
1325     // Operations that need to be done if the size changes.
1326     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1327                                                                         ALIGN  |
1328                                                                         REORDER );
1329
1330     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1331                 static_cast<OperationsMask>( onlyOnceOperations |
1332                                              sizeOperations ),
1333                 naturalSize.GetVectorXY() );
1334
1335     // Do not do again the only once operations.
1336     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1337
1338     // Do the size related operations again.
1339     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1340
1341     // Stores the natural size to avoid recalculate it again
1342     // unless the text/style changes.
1343     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1344
1345     mImpl->mRecalculateNaturalSize = false;
1346   }
1347   else
1348   {
1349     naturalSize = mImpl->mVisualModel->GetNaturalSize();
1350   }
1351
1352   return naturalSize;
1353 }
1354
1355 float Controller::GetHeightForWidth( float width )
1356 {
1357   // Make sure the model is up-to-date before layouting
1358   ProcessModifyEvents();
1359
1360   Size layoutSize;
1361   if( width != mImpl->mControlSize.width )
1362   {
1363     // Operations that can be done only once until the text changes.
1364     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1365                                                                            GET_SCRIPTS       |
1366                                                                            VALIDATE_FONTS    |
1367                                                                            GET_LINE_BREAKS   |
1368                                                                            GET_WORD_BREAKS   |
1369                                                                            BIDI_INFO         |
1370                                                                            SHAPE_TEXT        |
1371                                                                            GET_GLYPH_METRICS );
1372     // Make sure the model is up-to-date before layouting
1373     UpdateModel( onlyOnceOperations );
1374
1375     // Operations that need to be done if the size changes.
1376     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1377                                                                         ALIGN  |
1378                                                                         REORDER );
1379
1380     DoRelayout( Size( width, MAX_FLOAT ),
1381                 static_cast<OperationsMask>( onlyOnceOperations |
1382                                              sizeOperations ),
1383                 layoutSize );
1384
1385     // Do not do again the only once operations.
1386     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1387
1388     // Do the size related operations again.
1389     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1390   }
1391   else
1392   {
1393     layoutSize = mImpl->mVisualModel->GetActualSize();
1394   }
1395
1396   return layoutSize.height;
1397 }
1398
1399 bool Controller::Relayout( const Size& size )
1400 {
1401   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1402   {
1403     bool glyphsRemoved( false );
1404     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
1405     {
1406       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
1407       glyphsRemoved = true;
1408     }
1409
1410     // Not worth to relayout if width or height is equal to zero.
1411     return glyphsRemoved;
1412   }
1413
1414   if( size != mImpl->mControlSize )
1415   {
1416     // Operations that need to be done if the size changes.
1417     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1418                                                              LAYOUT                    |
1419                                                              ALIGN                     |
1420                                                              UPDATE_ACTUAL_SIZE        |
1421                                                              REORDER );
1422
1423     mImpl->mControlSize = size;
1424   }
1425
1426   // Make sure the model is up-to-date before layouting
1427   ProcessModifyEvents();
1428   UpdateModel( mImpl->mOperationsPending );
1429
1430   Size layoutSize;
1431   bool updated = DoRelayout( mImpl->mControlSize,
1432                              mImpl->mOperationsPending,
1433                              layoutSize );
1434
1435   // Do not re-do any operation until something changes.
1436   mImpl->mOperationsPending = NO_OPERATION;
1437
1438   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
1439   CalculateTextAlignment( size );
1440
1441   if( mImpl->mTextInput )
1442   {
1443     // Move the cursor, grab handle etc.
1444     updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize, mImpl->mAlignmentOffset ) || updated;
1445   }
1446
1447   return updated;
1448 }
1449
1450 void Controller::ProcessModifyEvents()
1451 {
1452   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
1453
1454   for( unsigned int i=0; i<events.size(); ++i )
1455   {
1456     if( REPLACE_TEXT == events[0].type )
1457     {
1458       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
1459       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
1460
1461       ReplaceTextEvent( events[0].text );
1462     }
1463     else if( INSERT_TEXT == events[0].type )
1464     {
1465       InsertTextEvent( events[0].text );
1466     }
1467     else if( DELETE_TEXT == events[0].type )
1468     {
1469       DeleteTextEvent();
1470     }
1471   }
1472
1473   // Discard temporary text
1474   events.clear();
1475 }
1476
1477 void Controller::ReplaceTextEvent( const std::string& text )
1478 {
1479   // Reset buffers.
1480   mImpl->mLogicalModel->mText.Clear();
1481   mImpl->mLogicalModel->mScriptRuns.Clear();
1482   mImpl->mLogicalModel->mFontRuns.Clear();
1483   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1484   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1485   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1486   mImpl->mLogicalModel->mCharacterDirections.Clear();
1487   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1488   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1489   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1490   mImpl->mVisualModel->mGlyphs.Clear();
1491   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1492   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1493   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1494   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1495   mImpl->mVisualModel->mGlyphPositions.Clear();
1496   mImpl->mVisualModel->mLines.Clear();
1497   mImpl->mVisualModel->ClearCaches();
1498
1499   //  Convert text into UTF-32
1500   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1501   utf32Characters.Resize( text.size() );
1502
1503   // This is a bit horrible but std::string returns a (signed) char*
1504   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1505
1506   // Transform a text array encoded in utf8 into an array encoded in utf32.
1507   // It returns the actual number of characters.
1508   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1509   utf32Characters.Resize( characterCount );
1510
1511   // Reset the cursor position
1512   if( mImpl->mTextInput )
1513   {
1514     mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
1515     // TODO - handle secondary cursor
1516   }
1517
1518   // The natural size needs to be re-calculated.
1519   mImpl->mRecalculateNaturalSize = true;
1520
1521   // Apply modifications to the model
1522   mImpl->mOperationsPending = ALL_OPERATIONS;
1523   UpdateModel( ALL_OPERATIONS );
1524   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1525                                                            ALIGN              |
1526                                                            UPDATE_ACTUAL_SIZE |
1527                                                            REORDER );
1528 }
1529
1530 void Controller::InsertTextEvent( const std::string& text )
1531 {
1532   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1533
1534   // TODO - Optimize this
1535   mImpl->mLogicalModel->mScriptRuns.Clear();
1536   mImpl->mLogicalModel->mFontRuns.Clear();
1537   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1538   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1539   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1540   mImpl->mLogicalModel->mCharacterDirections.Clear();
1541   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1542   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1543   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1544   mImpl->mVisualModel->mGlyphs.Clear();
1545   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1546   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1547   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1548   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1549   mImpl->mVisualModel->mGlyphPositions.Clear();
1550   mImpl->mVisualModel->mLines.Clear();
1551   mImpl->mVisualModel->ClearCaches();
1552
1553   //  Convert text into UTF-32
1554   Vector<Character> utf32Characters;
1555   utf32Characters.Resize( text.size() );
1556
1557   // This is a bit horrible but std::string returns a (signed) char*
1558   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1559
1560   // Transform a text array encoded in utf8 into an array encoded in utf32.
1561   // It returns the actual number of characters.
1562   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1563   utf32Characters.Resize( characterCount );
1564
1565   // Insert at current cursor position
1566   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1567   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1568
1569   if( cursorIndex < modifyText.Count() )
1570   {
1571     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
1572   }
1573   else
1574   {
1575     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
1576   }
1577
1578   // Advance the cursor position
1579   ++cursorIndex;
1580
1581   // The natural size needs to be re-calculated.
1582   mImpl->mRecalculateNaturalSize = true;
1583
1584   // Apply modifications to the model; TODO - Optimize this
1585   mImpl->mOperationsPending = ALL_OPERATIONS;
1586   UpdateModel( ALL_OPERATIONS );
1587   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1588                                                            ALIGN              |
1589                                                            UPDATE_ACTUAL_SIZE |
1590                                                            REORDER );
1591
1592   // Queue a cursor reposition event; this must wait until after DoRelayout()
1593   mImpl->mTextInput->mUpdateCursorPosition = true;
1594 }
1595
1596 void Controller::DeleteTextEvent()
1597 {
1598   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1599
1600   // TODO - Optimize this
1601   mImpl->mLogicalModel->mScriptRuns.Clear();
1602   mImpl->mLogicalModel->mFontRuns.Clear();
1603   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1604   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1605   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1606   mImpl->mLogicalModel->mCharacterDirections.Clear();
1607   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1608   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1609   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1610   mImpl->mVisualModel->mGlyphs.Clear();
1611   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1612   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1613   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1614   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1615   mImpl->mVisualModel->mGlyphPositions.Clear();
1616   mImpl->mVisualModel->mLines.Clear();
1617   mImpl->mVisualModel->ClearCaches();
1618
1619   // Delte at current cursor position
1620   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1621   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1622
1623   if( cursorIndex > 0 &&
1624       cursorIndex-1 < modifyText.Count() )
1625   {
1626     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
1627
1628     // Cursor position retreat
1629     --cursorIndex;
1630   }
1631
1632   // The natural size needs to be re-calculated.
1633   mImpl->mRecalculateNaturalSize = true;
1634
1635   // Apply modifications to the model; TODO - Optimize this
1636   mImpl->mOperationsPending = ALL_OPERATIONS;
1637   UpdateModel( ALL_OPERATIONS );
1638   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1639                                                            ALIGN              |
1640                                                            UPDATE_ACTUAL_SIZE |
1641                                                            REORDER );
1642
1643   // Queue a cursor reposition event; this must wait until after DoRelayout()
1644   mImpl->mTextInput->mUpdateCursorPosition = true;
1645 }
1646
1647 void Controller::UpdateModel( OperationsMask operationsRequired )
1648 {
1649   // Calculate the operations to be done.
1650   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1651
1652   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1653
1654   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
1655
1656   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1657   if( GET_LINE_BREAKS & operations )
1658   {
1659     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
1660     // calculate the bidirectional info for each 'paragraph'.
1661     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
1662     // is not shaped together).
1663     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
1664
1665     SetLineBreakInfo( utf32Characters,
1666                       lineBreakInfo );
1667   }
1668
1669   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1670   if( GET_WORD_BREAKS & operations )
1671   {
1672     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
1673     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
1674
1675     SetWordBreakInfo( utf32Characters,
1676                       wordBreakInfo );
1677   }
1678
1679   const bool getScripts = GET_SCRIPTS & operations;
1680   const bool validateFonts = VALIDATE_FONTS & operations;
1681
1682   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
1683   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
1684
1685   if( getScripts || validateFonts )
1686   {
1687     // Validates the fonts assigned by the application or assigns default ones.
1688     // It makes sure all the characters are going to be rendered by the correct font.
1689     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
1690
1691     if( getScripts )
1692     {
1693       // Retrieves the scripts used in the text.
1694       multilanguageSupport.SetScripts( utf32Characters,
1695                                        lineBreakInfo,
1696                                        scripts );
1697     }
1698
1699     if( validateFonts )
1700     {
1701       if( 0u == validFonts.Count() )
1702       {
1703         // Copy the requested font defaults received via the property system.
1704         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
1705         GetDefaultFonts( validFonts, numberOfCharacters );
1706       }
1707
1708       // Validates the fonts. If there is a character with no assigned font it sets a default one.
1709       // After this call, fonts are validated.
1710       multilanguageSupport.ValidateFonts( utf32Characters,
1711                                           scripts,
1712                                           validFonts );
1713     }
1714   }
1715
1716   Vector<Character> mirroredUtf32Characters;
1717   bool textMirrored = false;
1718   if( BIDI_INFO & operations )
1719   {
1720     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
1721     // bidirectional info.
1722
1723     Length numberOfParagraphs = 0u;
1724
1725     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
1726     for( Length index = 0u; index < numberOfCharacters; ++index )
1727     {
1728       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
1729       {
1730         ++numberOfParagraphs;
1731       }
1732     }
1733
1734     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1735     bidirectionalInfo.Reserve( numberOfParagraphs );
1736
1737     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1738     SetBidirectionalInfo( utf32Characters,
1739                           scripts,
1740                           lineBreakInfo,
1741                           bidirectionalInfo );
1742
1743     if( 0u != bidirectionalInfo.Count() )
1744     {
1745       // This paragraph has right to left text. Some characters may need to be mirrored.
1746       // TODO: consider if the mirrored string can be stored as well.
1747
1748       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
1749
1750       // Only set the character directions if there is right to left characters.
1751       Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
1752       directions.Resize( numberOfCharacters );
1753
1754       GetCharactersDirection( bidirectionalInfo,
1755                               directions );
1756     }
1757     else
1758     {
1759       // There is no right to left characters. Clear the directions vector.
1760       mImpl->mLogicalModel->mCharacterDirections.Clear();
1761     }
1762
1763    }
1764
1765   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1766   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1767   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1768   if( SHAPE_TEXT & operations )
1769   {
1770     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1771     // Shapes the text.
1772     ShapeText( textToShape,
1773                lineBreakInfo,
1774                scripts,
1775                validFonts,
1776                glyphs,
1777                glyphsToCharactersMap,
1778                charactersPerGlyph );
1779
1780     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
1781     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
1782     mImpl->mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
1783   }
1784
1785   const Length numberOfGlyphs = glyphs.Count();
1786
1787   if( GET_GLYPH_METRICS & operations )
1788   {
1789     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
1790   }
1791 }
1792
1793 bool Controller::DoRelayout( const Size& size,
1794                              OperationsMask operationsRequired,
1795                              Size& layoutSize )
1796 {
1797   bool viewUpdated( false );
1798
1799   // Calculate the operations to be done.
1800   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1801
1802   if( LAYOUT & operations )
1803   {
1804     // Some vectors with data needed to layout and reorder may be void
1805     // after the first time the text has been laid out.
1806     // Fill the vectors again.
1807
1808     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
1809
1810     if( 0u == numberOfGlyphs )
1811     {
1812       // Nothing else to do if there is no glyphs.
1813       return true;
1814     }
1815
1816     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1817     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1818     Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
1819     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1820     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1821     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1822
1823     // Set the layout parameters.
1824     LayoutParameters layoutParameters( size,
1825                                        mImpl->mLogicalModel->mText.Begin(),
1826                                        lineBreakInfo.Begin(),
1827                                        wordBreakInfo.Begin(),
1828                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
1829                                        numberOfGlyphs,
1830                                        glyphs.Begin(),
1831                                        glyphsToCharactersMap.Begin(),
1832                                        charactersPerGlyph.Begin() );
1833
1834     // The laid-out lines.
1835     // It's not possible to know in how many lines the text is going to be laid-out,
1836     // but it can be resized at least with the number of 'paragraphs' to avoid
1837     // some re-allocations.
1838     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1839
1840     // Delete any previous laid out lines before setting the new ones.
1841     lines.Clear();
1842
1843     // The capacity of the bidirectional paragraph info is the number of paragraphs.
1844     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
1845
1846     // Resize the vector of positions to have the same size than the vector of glyphs.
1847     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1848     glyphPositions.Resize( numberOfGlyphs );
1849
1850     // Update the visual model.
1851     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1852                                                    glyphPositions,
1853                                                    lines,
1854                                                    layoutSize );
1855
1856     if( viewUpdated )
1857     {
1858       // Reorder the lines
1859       if( REORDER & operations )
1860       {
1861         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1862
1863         // Check first if there are paragraphs with bidirectional info.
1864         if( 0u != bidirectionalInfo.Count() )
1865         {
1866           // Get the lines
1867           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
1868
1869           // Reorder the lines.
1870           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1871           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1872           ReorderLines( bidirectionalInfo,
1873                         lines,
1874                         lineBidirectionalInfoRuns );
1875
1876           // Set the bidirectional info into the model.
1877           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1878           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1879                                                        numberOfBidirectionalInfoRuns );
1880
1881           // Set the bidirectional info per line into the layout parameters.
1882           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1883           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1884
1885           // Get the character to glyph conversion table and set into the layout.
1886           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1887
1888           // Get the glyphs per character table and set into the layout.
1889           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1890
1891           // Re-layout the text. Reorder those lines with right to left characters.
1892           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1893                                                          glyphPositions );
1894
1895           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1896           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1897                  endIt = lineBidirectionalInfoRuns.End();
1898                it != endIt;
1899                ++it )
1900           {
1901             BidirectionalLineInfoRun& bidiLineInfo = *it;
1902
1903             free( bidiLineInfo.visualToLogicalMap );
1904           }
1905         }
1906       } // REORDER
1907
1908       if( ALIGN & operations )
1909       {
1910         mImpl->mLayoutEngine.Align( layoutParameters,
1911                                     layoutSize,
1912                                     lines,
1913                                     glyphPositions );
1914       }
1915
1916       // Sets the actual size.
1917       if( UPDATE_ACTUAL_SIZE & operations )
1918       {
1919         mImpl->mVisualModel->SetActualSize( layoutSize );
1920       }
1921     } // view updated
1922   }
1923   else
1924   {
1925     layoutSize = mImpl->mVisualModel->GetActualSize();
1926   }
1927
1928   return viewUpdated;
1929 }
1930
1931 void Controller::CalculateTextAlignment( const Size& size )
1932 {
1933   // Get the direction of the first character.
1934   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
1935
1936   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
1937
1938   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
1939   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
1940   if( firstParagraphDirection &&
1941       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
1942   {
1943     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
1944     {
1945       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
1946     }
1947     else
1948     {
1949       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
1950     }
1951   }
1952
1953   switch( horizontalAlignment )
1954   {
1955     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1956     {
1957       mImpl->mAlignmentOffset.x = 0.f;
1958       break;
1959     }
1960     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1961     {
1962       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1963       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
1964       break;
1965     }
1966     case LayoutEngine::HORIZONTAL_ALIGN_END:
1967     {
1968       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1969       break;
1970     }
1971   }
1972
1973   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1974   switch( verticalAlignment )
1975   {
1976     case LayoutEngine::VERTICAL_ALIGN_TOP:
1977     {
1978       mImpl->mAlignmentOffset.y = 0.f;
1979       break;
1980     }
1981     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1982     {
1983       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1984       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
1985       break;
1986     }
1987     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1988     {
1989       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1990       break;
1991     }
1992   }
1993 }
1994
1995 View& Controller::GetView()
1996 {
1997   return mImpl->mView;
1998 }
1999
2000 LayoutEngine& Controller::GetLayoutEngine()
2001 {
2002   return mImpl->mLayoutEngine;
2003 }
2004
2005 void Controller::RequestRelayout()
2006 {
2007   mImpl->mControlInterface.RequestTextRelayout();
2008 }
2009
2010 void Controller::KeyboardFocusGainEvent()
2011 {
2012   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
2013
2014   if( mImpl->mTextInput )
2015   {
2016     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
2017     mImpl->mTextInput->mEventQueue.push_back( event );
2018
2019     RequestRelayout();
2020   }
2021 }
2022
2023 void Controller::KeyboardFocusLostEvent()
2024 {
2025   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
2026
2027   if( mImpl->mTextInput )
2028   {
2029     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
2030     mImpl->mTextInput->mEventQueue.push_back( event );
2031
2032     RequestRelayout();
2033   }
2034 }
2035
2036 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2037 {
2038   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
2039
2040   if( mImpl->mTextInput &&
2041       keyEvent.state == KeyEvent::Down )
2042   {
2043     int keyCode = keyEvent.keyCode;
2044     const std::string& keyString = keyEvent.keyPressed;
2045
2046     // Pre-process to separate modifying events from non-modifying input events.
2047     if( Dali::DALI_KEY_ESCAPE == keyCode )
2048     {
2049       // Escape key is a special case which causes focus loss
2050       KeyboardFocusLostEvent();
2051     }
2052     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
2053              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
2054              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
2055              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
2056     {
2057       TextInput::Event event( TextInput::CURSOR_KEY_EVENT );
2058       event.p1.mInt = keyCode;
2059       mImpl->mTextInput->mEventQueue.push_back( event );
2060     }
2061     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
2062     {
2063       // Queue a delete event
2064       ModifyEvent event;
2065       event.type = DELETE_TEXT;
2066       mImpl->mModifyEvents.push_back( event );
2067     }
2068     else if( !keyString.empty() )
2069     {
2070       // Queue an insert event
2071       ModifyEvent event;
2072       event.type = INSERT_TEXT;
2073       event.text = keyString;
2074       mImpl->mModifyEvents.push_back( event );
2075     }
2076
2077     mImpl->mTextInput->ChangeState( TextInput::EDITING ); // todo Confirm this is the best place to change the state of
2078
2079     RequestRelayout();
2080   }
2081
2082   return false;
2083 }
2084
2085 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2086 {
2087   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
2088
2089   if( mImpl->mTextInput )
2090   {
2091     TextInput::Event event( TextInput::TAP_EVENT );
2092     event.p1.mUint = tapCount;
2093     event.p2.mFloat = x;
2094     event.p3.mFloat = y;
2095     mImpl->mTextInput->mEventQueue.push_back( event );
2096
2097     RequestRelayout();
2098   }
2099 }
2100
2101 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2102 {
2103   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected PanEvent" );
2104
2105   if( mImpl->mTextInput )
2106   {
2107     TextInput::Event event( TextInput::PAN_EVENT );
2108     event.p1.mInt = state;
2109     event.p2.mFloat = displacement.x;
2110     event.p3.mFloat = displacement.y;
2111     mImpl->mTextInput->mEventQueue.push_back( event );
2112
2113     RequestRelayout();
2114   }
2115 }
2116
2117 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
2118 {
2119   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
2120
2121   if( mImpl->mTextInput )
2122   {
2123     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
2124     event.p1.mUint  = state;
2125     event.p2.mFloat = x;
2126     event.p3.mFloat = y;
2127     mImpl->mTextInput->mEventQueue.push_back( event );
2128
2129     RequestRelayout();
2130   }
2131 }
2132
2133 Controller::~Controller()
2134 {
2135   delete mImpl;
2136 }
2137
2138 Controller::Controller( ControlInterface& controlInterface )
2139 : mImpl( NULL )
2140 {
2141   mImpl = new Controller::Impl( controlInterface );
2142 }
2143
2144 } // namespace Text
2145
2146 } // namespace Toolkit
2147
2148 } // namespace Dali