Merge remote-tracking branch 'origin/tizen' into new_text
[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 const std::string EMPTY_STRING;
48
49 enum ModifyType
50 {
51   REPLACE_TEXT, ///< Replace the entire text
52   INSERT_TEXT,  ///< Insert characters at the current cursor position
53   DELETE_TEXT   ///< Delete a character at the current cursor position
54 };
55
56 struct ModifyEvent
57 {
58   ModifyType type;
59   std::string text;
60 };
61
62 } // namespace
63
64 namespace Dali
65 {
66
67 namespace Toolkit
68 {
69
70 namespace Text
71 {
72
73 struct Controller::TextInput
74 {
75   // Used to queue input events until DoRelayout()
76   enum EventType
77   {
78     KEYBOARD_FOCUS_GAIN_EVENT,
79     KEYBOARD_FOCUS_LOST_EVENT,
80     CURSOR_KEY_EVENT,
81     TAP_EVENT,
82     PAN_EVENT,
83     GRAB_HANDLE_EVENT
84   };
85
86   union Param
87   {
88     int mInt;
89     unsigned int mUint;
90     float mFloat;
91   };
92
93   struct Event
94   {
95     Event( EventType eventType )
96     : type( eventType )
97     {
98       p1.mInt = 0;
99       p2.mInt = 0;
100     }
101
102     EventType type;
103     Param p1;
104     Param p2;
105     Param p3;
106   };
107
108   enum State
109   {
110     INACTIVE,
111     SELECTING,
112     EDITING
113   };
114
115   TextInput( LogicalModelPtr logicalModel,
116              VisualModelPtr visualModel,
117              DecoratorPtr decorator )
118   : mLogicalModel( logicalModel ),
119     mVisualModel( visualModel ),
120     mDecorator( decorator ),
121     mState( INACTIVE ),
122     mPrimaryCursorPosition( 0u ),
123     mSecondaryCursorPosition( 0u ),
124     mDecoratorUpdated( false ),
125     mCursorBlinkEnabled( true ),
126     mGrabHandleEnabled( false ),
127     mGrabHandlePopupEnabled( false ),
128     mSelectionEnabled( false ),
129     mHorizontalScrollingEnabled( true ),
130     mVerticalScrollingEnabled( false ),
131     mUpdateCursorPosition( false )
132   {
133   }
134
135   /**
136    * @brief Helper to move the cursor, grab handle etc.
137    */
138   bool ProcessInputEvents( const Vector2& controlSize )
139   {
140     mDecoratorUpdated = false;
141
142     if( mDecorator )
143     {
144       for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
145       {
146         switch( iter->type )
147         {
148           case KEYBOARD_FOCUS_GAIN_EVENT:
149           {
150             OnKeyboardFocus( true );
151             break;
152           }
153           case KEYBOARD_FOCUS_LOST_EVENT:
154           {
155             OnKeyboardFocus( false );
156             break;
157           }
158           case CURSOR_KEY_EVENT:
159           {
160             OnCursorKeyEvent( *iter );
161             break;
162           }
163           case TAP_EVENT:
164           {
165             OnTapEvent( *iter );
166             break;
167           }
168           case PAN_EVENT:
169           {
170             OnPanEvent( *iter, controlSize );
171             break;
172           }
173           case GRAB_HANDLE_EVENT:
174           {
175             OnGrabHandleEvent( *iter );
176             break;
177           }
178         }
179       }
180     }
181
182     // The cursor must also be repositioned after inserts into the model
183     if( mUpdateCursorPosition )
184     {
185       UpdateCursorPosition();
186       mUpdateCursorPosition = false;
187     }
188
189     mEventQueue.clear();
190
191     return mDecoratorUpdated;
192   }
193
194   void OnKeyboardFocus( bool hasFocus )
195   {
196     if( !hasFocus )
197     {
198       ChangeState( INACTIVE );
199     }
200     else
201     {
202       ChangeState( EDITING );
203     }
204   }
205
206   void OnCursorKeyEvent( const Event& event )
207   {
208     int keyCode = event.p1.mInt;
209
210     if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
211     {
212       // TODO
213     }
214     else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
215     {
216       // TODO
217     }
218     else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
219     {
220       // TODO
221     }
222     else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
223     {
224       // TODO
225     }
226   }
227
228   void HandleCursorKey( int keyCode )
229   {
230     // TODO
231   }
232
233   void OnTapEvent( const Event& event )
234   {
235     unsigned int tapCount = event.p1.mUint;
236
237     if( 1u == tapCount )
238     {
239       ChangeState( EDITING );
240
241       float xPosition = event.p2.mFloat;
242       float yPosition = event.p3.mFloat;
243       float height(0.0f);
244       GetClosestCursorPosition( mPrimaryCursorPosition, xPosition, yPosition, height );
245       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
246       mUpdateCursorPosition = false;
247
248       mDecoratorUpdated = true;
249     }
250     else if( mSelectionEnabled &&
251              2u == tapCount )
252     {
253       ChangeState( SELECTING );
254     }
255   }
256
257   void OnPanEvent( const Event& event, const Vector2& controlSize )
258   {
259     int state = event.p1.mInt;
260
261     if( Gesture::Started    == state ||
262         Gesture::Continuing == state )
263     {
264       const Vector2& actualSize = mVisualModel->GetActualSize();
265
266       if( mHorizontalScrollingEnabled )
267       {
268         float displacementX = event.p2.mFloat;
269         mScrollPosition.x += displacementX;
270
271         // Clamp between -space & 0
272         float contentWidth = actualSize.width;
273         float space = (contentWidth > controlSize.width) ? contentWidth - controlSize.width : 0.0f;
274         mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x;
275         mScrollPosition.x = ( mScrollPosition.x > 0 )      ?      0 : mScrollPosition.x;
276
277         mDecoratorUpdated = true;
278       }
279       if( mVerticalScrollingEnabled )
280       {
281         float displacementY = event.p3.mFloat;
282         mScrollPosition.y += displacementY;
283
284         // Clamp between -space & 0
285         float space = (actualSize.height > controlSize.height) ? actualSize.height - controlSize.height : 0.0f;
286         mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y;
287         mScrollPosition.y = ( mScrollPosition.y > 0 )      ?      0 : mScrollPosition.y;
288
289         mDecoratorUpdated = true;
290       }
291     }
292   }
293
294   void OnGrabHandleEvent( const Event& event )
295   {
296     unsigned int state = event.p1.mUint;
297
298     if( GRAB_HANDLE_PRESSED == state )
299     {
300       float xPosition = event.p2.mFloat;
301       float yPosition = event.p3.mFloat;
302       float height(0.0f);
303
304       GetClosestCursorPosition( mPrimaryCursorPosition, xPosition, yPosition, height );
305
306       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
307       mDecorator->HidePopup();
308       mDecoratorUpdated = true;
309     }
310     else if ( mGrabHandlePopupEnabled &&
311               GRAB_HANDLE_RELEASED == state )
312     {
313       mDecorator->ShowPopup();
314     }
315   }
316
317   void ChangeState( State newState )
318   {
319     if( mState != newState )
320     {
321       mState = newState;
322
323       if( INACTIVE == mState )
324       {
325         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
326         mDecorator->StopCursorBlink();
327         mDecorator->SetGrabHandleActive( false );
328         mDecorator->SetSelectionActive( false );
329         mDecorator->HidePopup();
330         mDecoratorUpdated = true;
331       }
332       else if ( SELECTING == mState )
333       {
334         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
335         mDecorator->StopCursorBlink();
336         mDecorator->SetGrabHandleActive( false );
337         mDecorator->SetSelectionActive( true );
338         mDecoratorUpdated = true;
339       }
340       else if( EDITING == mState )
341       {
342         mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
343         if( mCursorBlinkEnabled )
344         {
345           mDecorator->StartCursorBlink();
346         }
347         if( mGrabHandleEnabled )
348         {
349           mDecorator->SetGrabHandleActive( true );
350         }
351         mDecorator->SetSelectionActive( false );
352         mDecoratorUpdated = true;
353       }
354     }
355   }
356
357   LineIndex GetClosestLine( float y )
358   {
359     LineIndex lineIndex( 0u );
360
361     const Vector<LineRun>& lines = mVisualModel->mLines;
362     for( float totalHeight = 0; lineIndex < lines.Count(); ++lineIndex )
363     {
364       totalHeight += lines[lineIndex].lineSize.height;
365       if( y < totalHeight )
366       {
367         break;
368       }
369     }
370
371     return lineIndex;
372   }
373
374   void GetClosestCursorPosition( CharacterIndex& logical, float& visualX, float& visualY, float& height )
375   {
376     Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
377     Length numberOfLines  = mVisualModel->mLines.Count();
378     if( 0 == numberOfGlyphs ||
379         0 == numberOfLines )
380     {
381       return;
382     }
383
384     // Transform to visual model coords
385     visualX -= mScrollPosition.x;
386     visualY -= mScrollPosition.y;
387
388     // Find which line is closest
389     LineIndex lineIndex( GetClosestLine( visualY ) );
390
391     const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
392     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
393
394     const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
395     const Vector2* const positionsBuffer = positions.Begin();
396
397     unsigned int closestGlyph = 0;
398     bool leftOfGlyph( false ); // which side of the glyph?
399     float closestDistance = MAX_FLOAT;
400
401     const LineRun& line = mVisualModel->mLines[lineIndex];
402     GlyphIndex startGlyph = line.glyphIndex;
403     GlyphIndex endGlyph   = line.glyphIndex + line.numberOfGlyphs;
404     DALI_ASSERT_DEBUG( endGlyph <= glyphs.Count() && "Invalid line info" );
405
406     for( GlyphIndex i = startGlyph; i < endGlyph; ++i )
407     {
408       const GlyphInfo& glyphInfo = *( glyphsBuffer + i );
409       const Vector2& position = *( positionsBuffer + i );
410       float glyphX = position.x + glyphInfo.width*0.5f;
411       float glyphY = position.y + glyphInfo.height*0.5f;
412
413       float distanceToGlyph = fabsf( glyphX - visualX ) + fabsf( glyphY - visualY );
414
415       if( distanceToGlyph < closestDistance )
416       {
417         closestDistance = distanceToGlyph;
418         closestGlyph = i;
419         leftOfGlyph = ( visualX < glyphX );
420       }
421     }
422
423     // Calculate the logical position
424     logical = mVisualModel->GetCharacterIndex( closestGlyph );
425
426     // Returns the visual position of the glyph
427     visualX = positions[closestGlyph].x;
428     if( !leftOfGlyph )
429     {
430       visualX += glyphs[closestGlyph].width;
431
432       //if( LTR ) TODO
433         ++logical;
434     }
435     else// if ( RTL ) TODO
436     {
437       //++logical;
438     }
439     visualY = 0.0f;
440
441     height = line.lineSize.height;
442   }
443
444   void UpdateCursorPosition()
445   {
446     if( 0 == mVisualModel->mGlyphs.Count() )
447     {
448       return;
449     }
450
451     // FIXME GetGlyphIndex() is behaving strangely
452 #if 0
453     GlyphIndex cursorGlyph = mVisualModel->GetGlyphIndex( mPrimaryCursorPosition );
454 #else
455     GlyphIndex cursorGlyph( 0u );
456     for( cursorGlyph = 0; cursorGlyph < mVisualModel->mGlyphs.Count(); ++cursorGlyph )
457     {
458       if( mPrimaryCursorPosition == mVisualModel->GetCharacterIndex( cursorGlyph ) )
459       {
460         break;
461       }
462     }
463 #endif
464
465     float visualX( 0.0f );
466     float visualY( 0.0f );
467     LineIndex lineIndex( 0u );
468     const Vector<LineRun>& lineRuns = mVisualModel->mLines;
469
470     if( cursorGlyph > 0 )
471     {
472       --cursorGlyph;
473
474       visualX = mVisualModel->mGlyphPositions[ cursorGlyph ].x;
475       //if( LTR ) TODO
476         visualX += mVisualModel->mGlyphs[ cursorGlyph ].width;
477
478       // Find the line height
479       for( GlyphIndex lastGlyph = 0; lineIndex < lineRuns.Count(); ++lineIndex )
480       {
481         lastGlyph = (lineRuns[lineIndex].glyphIndex + lineRuns[lineIndex].numberOfGlyphs);
482         if( cursorGlyph < lastGlyph )
483         {
484           break;
485         }
486       }
487     }
488
489     mDecorator->SetPosition( PRIMARY_CURSOR, visualX, visualY, lineRuns[lineIndex].lineSize.height );
490     mDecoratorUpdated = true;
491   }
492
493   LogicalModelPtr mLogicalModel;
494   VisualModelPtr  mVisualModel;
495   DecoratorPtr    mDecorator;
496
497   std::string mPlaceholderText;
498
499   /**
500    * This is used to delay handling events until after the model has been updated.
501    * The number of updates to the model is minimized to improve performance.
502    */
503   vector<Event> mEventQueue; ///< The queue of touch events etc.
504
505   State mState; ///< Selection mode, edit mode etc.
506
507   CharacterIndex mPrimaryCursorPosition;   ///< Index into logical model for primary cursor
508   CharacterIndex mSecondaryCursorPosition; ///< Index into logical model for secondary cursor
509
510   /**
511    * 0,0 means that the top-left corner of the layout matches the top-left corner of the UI control.
512    * Typically this will have a negative value with scrolling occurs.
513    */
514   Vector2 mScrollPosition; ///< The text is offset by this position when scrolling.
515
516   bool mDecoratorUpdated           : 1; ///< True if the decorator was updated during event processing
517   bool mCursorBlinkEnabled         : 1; ///< True if cursor should blink when active
518   bool mGrabHandleEnabled          : 1; ///< True if grab handle is enabled
519   bool mGrabHandlePopupEnabled     : 1; ///< True if the grab handle popu-up should be shown
520   bool mSelectionEnabled           : 1; ///< True if selection handles, highlight etc. are enabled
521   bool mHorizontalScrollingEnabled : 1; ///< True if horizontal scrolling is enabled
522   bool mVerticalScrollingEnabled   : 1; ///< True if vertical scrolling is enabled
523   bool mUpdateCursorPosition       : 1; ///< True if the visual position of the cursor must be recalculated
524 };
525
526 struct Controller::FontDefaults
527 {
528   FontDefaults()
529   : mDefaultPointSize(0.0f),
530     mFontId(0u)
531   {
532   }
533
534   FontId GetFontId( TextAbstraction::FontClient& fontClient )
535   {
536     if( !mFontId )
537     {
538       Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
539       mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
540     }
541
542     return mFontId;
543   }
544
545   std::string mDefaultFontFamily;
546   std::string mDefaultFontStyle;
547   float mDefaultPointSize;
548   FontId mFontId;
549 };
550
551 struct Controller::Impl
552 {
553   Impl( ControlInterface& controlInterface )
554   : mControlInterface( controlInterface ),
555     mLogicalModel(),
556     mVisualModel(),
557     mFontDefaults( NULL ),
558     mTextInput( NULL ),
559     mFontClient(),
560     mView(),
561     mLayoutEngine(),
562     mModifyEvents(),
563     mControlSize(),
564     mOperationsPending( NO_OPERATION ),
565     mRecalculateNaturalSize( true )
566   {
567     mLogicalModel = LogicalModel::New();
568     mVisualModel  = VisualModel::New();
569
570     mFontClient = TextAbstraction::FontClient::Get();
571
572     mView.SetVisualModel( mVisualModel );
573   }
574
575   ~Impl()
576   {
577     delete mTextInput;
578   }
579
580   ControlInterface& mControlInterface;     ///< Reference to the text controller.
581   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
582   VisualModelPtr  mVisualModel;            ///< Pointer to the visual model.
583   FontDefaults* mFontDefaults;             ///< Avoid allocating this when the user does not specify a font.
584   Controller::TextInput* mTextInput;       ///< Avoid allocating everything for text input until EnableTextInput().
585   TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
586   View mView;                              ///< The view interface to the rendering back-end.
587   LayoutEngine mLayoutEngine;              ///< The layout engine.
588   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
589   Size mControlSize;                       ///< The size of the control.
590   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
591   bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
592 };
593
594 ControllerPtr Controller::New( ControlInterface& controlInterface )
595 {
596   return ControllerPtr( new Controller( controlInterface ) );
597 }
598
599 void Controller::SetText( const std::string& text )
600 {
601   // Cancel previously queued inserts etc.
602   mImpl->mModifyEvents.clear();
603
604   // Keep until size negotiation
605   ModifyEvent event;
606   event.type = REPLACE_TEXT;
607   event.text = text;
608   mImpl->mModifyEvents.push_back( event );
609
610   if( mImpl->mTextInput )
611   {
612     // Cancel previously queued events
613     mImpl->mTextInput->mEventQueue.clear();
614
615     // TODO - Hide selection decorations
616   }
617 }
618
619 void Controller::GetText( std::string& text ) const
620 {
621   if( !mImpl->mModifyEvents.empty() &&
622        REPLACE_TEXT == mImpl->mModifyEvents[0].type )
623   {
624     text = mImpl->mModifyEvents[0].text;
625   }
626   else
627   {
628     // TODO - Convert from UTF-32
629   }
630 }
631
632 void Controller::SetPlaceholderText( const std::string& text )
633 {
634   if( !mImpl->mTextInput )
635   {
636     mImpl->mTextInput->mPlaceholderText = text;
637   }
638 }
639
640 void Controller::GetPlaceholderText( std::string& text ) const
641 {
642   if( !mImpl->mTextInput )
643   {
644     text = mImpl->mTextInput->mPlaceholderText;
645   }
646 }
647
648 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
649 {
650   if( !mImpl->mFontDefaults )
651   {
652     mImpl->mFontDefaults = new Controller::FontDefaults();
653   }
654
655   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
656   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
657   mImpl->mOperationsPending = ALL_OPERATIONS;
658   mImpl->mRecalculateNaturalSize = true;
659 }
660
661 const std::string& Controller::GetDefaultFontFamily() const
662 {
663   if( mImpl->mFontDefaults )
664   {
665     return mImpl->mFontDefaults->mDefaultFontFamily;
666   }
667
668   return EMPTY_STRING;
669 }
670
671 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
672 {
673   if( !mImpl->mFontDefaults )
674   {
675     mImpl->mFontDefaults = new Controller::FontDefaults();
676   }
677
678   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
679   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
680   mImpl->mOperationsPending = ALL_OPERATIONS;
681   mImpl->mRecalculateNaturalSize = true;
682 }
683
684 const std::string& Controller::GetDefaultFontStyle() const
685 {
686   if( mImpl->mFontDefaults )
687   {
688     return mImpl->mFontDefaults->mDefaultFontStyle;
689   }
690
691   return EMPTY_STRING;
692 }
693
694 void Controller::SetDefaultPointSize( float pointSize )
695 {
696   if( !mImpl->mFontDefaults )
697   {
698     mImpl->mFontDefaults = new Controller::FontDefaults();
699   }
700
701   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
702   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
703   mImpl->mOperationsPending = ALL_OPERATIONS;
704   mImpl->mRecalculateNaturalSize = true;
705 }
706
707 float Controller::GetDefaultPointSize() const
708 {
709   if( mImpl->mFontDefaults )
710   {
711     return mImpl->mFontDefaults->mDefaultPointSize;
712   }
713
714   return 0.0f;
715 }
716
717 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
718 {
719   if( mImpl->mFontDefaults )
720   {
721     FontRun fontRun;
722     fontRun.characterRun.characterIndex = 0;
723     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
724     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
725     fontRun.isDefault = true;
726
727     fonts.PushBack( fontRun );
728   }
729 }
730
731 void Controller::EnableTextInput( DecoratorPtr decorator )
732 {
733   if( !mImpl->mTextInput )
734   {
735     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
736   }
737 }
738
739 void Controller::SetEnableCursorBlink( bool enable )
740 {
741   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
742
743   if( mImpl->mTextInput )
744   {
745     mImpl->mTextInput->mCursorBlinkEnabled = enable;
746
747     if( !enable &&
748         mImpl->mTextInput->mDecorator )
749     {
750       mImpl->mTextInput->mDecorator->StopCursorBlink();
751     }
752   }
753 }
754
755 bool Controller::GetEnableCursorBlink() const
756 {
757   if( mImpl->mTextInput )
758   {
759     return mImpl->mTextInput->mCursorBlinkEnabled;
760   }
761
762   return false;
763 }
764
765 const Vector2& Controller::GetScrollPosition() const
766 {
767   if( mImpl->mTextInput )
768   {
769     return mImpl->mTextInput->mScrollPosition;
770   }
771
772   return Vector2::ZERO;
773 }
774
775 Vector3 Controller::GetNaturalSize()
776 {
777   Vector3 naturalSize;
778
779   // Make sure the model is up-to-date before layouting
780   ProcessModifyEvents();
781
782   if( mImpl->mRecalculateNaturalSize )
783   {
784     // Operations that can be done only once until the text changes.
785     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
786                                                                            GET_SCRIPTS       |
787                                                                            VALIDATE_FONTS    |
788                                                                            GET_LINE_BREAKS   |
789                                                                            GET_WORD_BREAKS   |
790                                                                            BIDI_INFO         |
791                                                                            SHAPE_TEXT        |
792                                                                            GET_GLYPH_METRICS );
793     // Make sure the model is up-to-date before layouting
794     UpdateModel( onlyOnceOperations );
795
796     // Operations that need to be done if the size changes.
797     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
798                                                                         ALIGN  |
799                                                                         REORDER );
800
801     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
802                 static_cast<OperationsMask>( onlyOnceOperations |
803                                              sizeOperations ),
804                 naturalSize.GetVectorXY() );
805
806     // Do not do again the only once operations.
807     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
808
809     // Do the size related operations again.
810     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
811
812     // Stores the natural size to avoid recalculate it again
813     // unless the text/style changes.
814     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
815
816     mImpl->mRecalculateNaturalSize = false;
817   }
818   else
819   {
820     naturalSize = mImpl->mVisualModel->GetNaturalSize();
821   }
822
823   return naturalSize;
824 }
825
826 float Controller::GetHeightForWidth( float width )
827 {
828   // Make sure the model is up-to-date before layouting
829   ProcessModifyEvents();
830
831   Size layoutSize;
832   if( width != mImpl->mControlSize.width )
833   {
834     // Operations that can be done only once until the text changes.
835     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
836                                                                            GET_SCRIPTS       |
837                                                                            VALIDATE_FONTS    |
838                                                                            GET_LINE_BREAKS   |
839                                                                            GET_WORD_BREAKS   |
840                                                                            BIDI_INFO         |
841                                                                            SHAPE_TEXT        |
842                                                                            GET_GLYPH_METRICS );
843     // Make sure the model is up-to-date before layouting
844     UpdateModel( onlyOnceOperations );
845
846     // Operations that need to be done if the size changes.
847     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
848                                                                         ALIGN  |
849                                                                         REORDER );
850
851     DoRelayout( Size( width, MAX_FLOAT ),
852                 static_cast<OperationsMask>( onlyOnceOperations |
853                                              sizeOperations ),
854                 layoutSize );
855
856     // Do not do again the only once operations.
857     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
858
859     // Do the size related operations again.
860     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
861   }
862   else
863   {
864     layoutSize = mImpl->mVisualModel->GetActualSize();
865   }
866
867   return layoutSize.height;
868 }
869
870 bool Controller::Relayout( const Vector2& size )
871 {
872   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
873   {
874     bool glyphsRemoved( false );
875     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
876     {
877       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
878       glyphsRemoved = true;
879     }
880
881     // Not worth to relayout if width or height is equal to zero.
882     return glyphsRemoved;
883   }
884
885   if( size != mImpl->mControlSize )
886   {
887     // Operations that need to be done if the size changes.
888     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
889                                                              LAYOUT                    |
890                                                              ALIGN                     |
891                                                              UPDATE_ACTUAL_SIZE        |
892                                                              REORDER );
893
894     mImpl->mControlSize = size;
895   }
896
897   // Make sure the model is up-to-date before layouting
898   ProcessModifyEvents();
899   UpdateModel( mImpl->mOperationsPending );
900
901   Size layoutSize;
902   bool updated = DoRelayout( mImpl->mControlSize,
903                              mImpl->mOperationsPending,
904                              layoutSize );
905
906   // Do not re-do any operation until something changes.
907   mImpl->mOperationsPending = NO_OPERATION;
908
909   if( mImpl->mTextInput )
910   {
911     // Move the cursor, grab handle etc.
912     updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize ) || updated;
913   }
914
915   return updated;
916 }
917
918 void Controller::ProcessModifyEvents()
919 {
920   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
921
922   for( unsigned int i=0; i<events.size(); ++i )
923   {
924     if( REPLACE_TEXT == events[0].type )
925     {
926       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
927       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
928
929       ReplaceTextEvent( events[0].text );
930     }
931     else if( INSERT_TEXT == events[0].type )
932     {
933       InsertTextEvent( events[0].text );
934     }
935     else if( DELETE_TEXT == events[0].type )
936     {
937       DeleteTextEvent();
938     }
939   }
940
941   // Discard temporary text
942   events.clear();
943 }
944
945 void Controller::ReplaceTextEvent( const std::string& text )
946 {
947   // Reset buffers.
948   mImpl->mLogicalModel->mText.Clear();
949   mImpl->mLogicalModel->mScriptRuns.Clear();
950   mImpl->mLogicalModel->mFontRuns.Clear();
951   mImpl->mLogicalModel->mLineBreakInfo.Clear();
952   mImpl->mLogicalModel->mWordBreakInfo.Clear();
953   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
954   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
955   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
956   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
957   mImpl->mVisualModel->mGlyphs.Clear();
958   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
959   mImpl->mVisualModel->mCharactersToGlyph.Clear();
960   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
961   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
962   mImpl->mVisualModel->mGlyphPositions.Clear();
963   mImpl->mVisualModel->mLines.Clear();
964
965   //  Convert text into UTF-32
966   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
967   utf32Characters.Resize( text.size() );
968
969   // This is a bit horrible but std::string returns a (signed) char*
970   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
971
972   // Transform a text array encoded in utf8 into an array encoded in utf32.
973   // It returns the actual number of characters.
974   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
975   utf32Characters.Resize( characterCount );
976
977   // Reset the cursor position
978   if( mImpl->mTextInput )
979   {
980     mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
981     // TODO - handle secondary cursor
982   }
983
984   // The natural size needs to be re-calculated.
985   mImpl->mRecalculateNaturalSize = true;
986
987   // Apply modifications to the model
988   mImpl->mOperationsPending = ALL_OPERATIONS;
989   UpdateModel( ALL_OPERATIONS );
990   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
991                                                            ALIGN              |
992                                                            UPDATE_ACTUAL_SIZE |
993                                                            REORDER );
994 }
995
996 void Controller::InsertTextEvent( const std::string& text )
997 {
998   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
999
1000   // TODO - Optimize this
1001   mImpl->mLogicalModel->mScriptRuns.Clear();
1002   mImpl->mLogicalModel->mFontRuns.Clear();
1003   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1004   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1005   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1006   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1007   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1008   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1009   mImpl->mVisualModel->mGlyphs.Clear();
1010   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1011   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1012   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1013   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1014   mImpl->mVisualModel->mGlyphPositions.Clear();
1015   mImpl->mVisualModel->mLines.Clear();
1016
1017   //  Convert text into UTF-32
1018   Vector<Character> utf32Characters;
1019   utf32Characters.Resize( text.size() );
1020
1021   // This is a bit horrible but std::string returns a (signed) char*
1022   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1023
1024   // Transform a text array encoded in utf8 into an array encoded in utf32.
1025   // It returns the actual number of characters.
1026   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1027   utf32Characters.Resize( characterCount );
1028
1029   // Insert at current cursor position
1030   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1031   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1032
1033   if( cursorIndex < modifyText.Count() )
1034   {
1035     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
1036   }
1037   else
1038   {
1039     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
1040   }
1041
1042   // Advance the cursor position
1043   ++cursorIndex;
1044
1045   // The natural size needs to be re-calculated.
1046   mImpl->mRecalculateNaturalSize = true;
1047
1048   // Apply modifications to the model; TODO - Optimize this
1049   mImpl->mOperationsPending = ALL_OPERATIONS;
1050   UpdateModel( ALL_OPERATIONS );
1051   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1052                                                            ALIGN              |
1053                                                            UPDATE_ACTUAL_SIZE |
1054                                                            REORDER );
1055
1056   // Queue a cursor reposition event; this must wait until after DoRelayout()
1057   mImpl->mTextInput->mUpdateCursorPosition = true;
1058 }
1059
1060 void Controller::DeleteTextEvent()
1061 {
1062   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1063
1064   // TODO - Optimize this
1065   mImpl->mLogicalModel->mScriptRuns.Clear();
1066   mImpl->mLogicalModel->mFontRuns.Clear();
1067   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1068   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1069   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1070   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1071   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1072   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1073   mImpl->mVisualModel->mGlyphs.Clear();
1074   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1075   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1076   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1077   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1078   mImpl->mVisualModel->mGlyphPositions.Clear();
1079   mImpl->mVisualModel->mLines.Clear();
1080
1081   // Delte at current cursor position
1082   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1083   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1084
1085   if( cursorIndex > 0 &&
1086       cursorIndex-1 < modifyText.Count() )
1087   {
1088     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
1089
1090     // Cursor position retreat
1091     --cursorIndex;
1092   }
1093
1094   // The natural size needs to be re-calculated.
1095   mImpl->mRecalculateNaturalSize = true;
1096
1097   // Apply modifications to the model; TODO - Optimize this
1098   mImpl->mOperationsPending = ALL_OPERATIONS;
1099   UpdateModel( ALL_OPERATIONS );
1100   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1101                                                            ALIGN              |
1102                                                            UPDATE_ACTUAL_SIZE |
1103                                                            REORDER );
1104
1105   // Queue a cursor reposition event; this must wait until after DoRelayout()
1106   mImpl->mTextInput->mUpdateCursorPosition = true;
1107 }
1108
1109 void Controller::UpdateModel( OperationsMask operationsRequired )
1110 {
1111   // Calculate the operations to be done.
1112   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1113
1114   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1115
1116   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
1117
1118   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1119   if( GET_LINE_BREAKS & operations )
1120   {
1121     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
1122     // calculate the bidirectional info for each 'paragraph'.
1123     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
1124     // is not shaped together).
1125     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
1126
1127     SetLineBreakInfo( utf32Characters,
1128                       lineBreakInfo );
1129   }
1130
1131   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1132   if( GET_WORD_BREAKS & operations )
1133   {
1134     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
1135     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
1136
1137     SetWordBreakInfo( utf32Characters,
1138                       wordBreakInfo );
1139   }
1140
1141   const bool getScripts = GET_SCRIPTS & operations;
1142   const bool validateFonts = VALIDATE_FONTS & operations;
1143
1144   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
1145   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
1146
1147   if( getScripts || validateFonts )
1148   {
1149     // Validates the fonts assigned by the application or assigns default ones.
1150     // It makes sure all the characters are going to be rendered by the correct font.
1151     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
1152
1153     if( getScripts )
1154     {
1155       // Retrieves the scripts used in the text.
1156       multilanguageSupport.SetScripts( utf32Characters,
1157                                        lineBreakInfo,
1158                                        scripts );
1159     }
1160
1161     if( validateFonts )
1162     {
1163       if( 0u == validFonts.Count() )
1164       {
1165         // Copy the requested font defaults received via the property system.
1166         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
1167         GetDefaultFonts( validFonts, numberOfCharacters );
1168       }
1169
1170       // Validates the fonts. If there is a character with no assigned font it sets a default one.
1171       // After this call, fonts are validated.
1172       multilanguageSupport.ValidateFonts( utf32Characters,
1173                                           scripts,
1174                                           validFonts );
1175     }
1176   }
1177
1178   Vector<Character> mirroredUtf32Characters;
1179   bool textMirrored = false;
1180   if( BIDI_INFO & operations )
1181   {
1182     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
1183     // bidirectional info.
1184
1185     Length numberOfParagraphs = 0u;
1186
1187     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
1188     for( Length index = 0u; index < numberOfCharacters; ++index )
1189     {
1190       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
1191       {
1192         ++numberOfParagraphs;
1193       }
1194     }
1195
1196     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1197     bidirectionalInfo.Reserve( numberOfParagraphs );
1198
1199     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1200     SetBidirectionalInfo( utf32Characters,
1201                           scripts,
1202                           lineBreakInfo,
1203                           bidirectionalInfo );
1204
1205     if( 0u != bidirectionalInfo.Count() )
1206     {
1207       // This paragraph has right to left text. Some characters may need to be mirrored.
1208       // TODO: consider if the mirrored string can be stored as well.
1209
1210       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
1211     }
1212   }
1213
1214   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1215   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1216   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1217   if( SHAPE_TEXT & operations )
1218   {
1219     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1220     // Shapes the text.
1221     ShapeText( textToShape,
1222                lineBreakInfo,
1223                scripts,
1224                validFonts,
1225                glyphs,
1226                glyphsToCharactersMap,
1227                charactersPerGlyph );
1228   }
1229
1230   const Length numberOfGlyphs = glyphs.Count();
1231
1232   if( GET_GLYPH_METRICS & operations )
1233   {
1234     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
1235   }
1236
1237   if( 0u != numberOfGlyphs )
1238   {
1239     // Create the glyph to character conversion table and the 'number of glyphs' per character.
1240     mImpl->mVisualModel->CreateCharacterToGlyphTable(numberOfCharacters );
1241     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
1242   }
1243 }
1244
1245 bool Controller::DoRelayout( const Vector2& size,
1246                              OperationsMask operationsRequired,
1247                              Size& layoutSize )
1248 {
1249   bool viewUpdated( false );
1250
1251   // Calculate the operations to be done.
1252   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1253
1254   if( LAYOUT & operations )
1255   {
1256     // Some vectors with data needed to layout and reorder may be void
1257     // after the first time the text has been laid out.
1258     // Fill the vectors again.
1259
1260     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
1261
1262     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1263     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1264     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1265     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1266     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1267
1268     // Set the layout parameters.
1269     LayoutParameters layoutParameters( size,
1270                                        mImpl->mLogicalModel->mText.Begin(),
1271                                        lineBreakInfo.Begin(),
1272                                        wordBreakInfo.Begin(),
1273                                        numberOfGlyphs,
1274                                        glyphs.Begin(),
1275                                        glyphsToCharactersMap.Begin(),
1276                                        charactersPerGlyph.Begin() );
1277
1278     // The laid-out lines.
1279     // It's not possible to know in how many lines the text is going to be laid-out,
1280     // but it can be resized at least with the number of 'paragraphs' to avoid
1281     // some re-allocations.
1282     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1283
1284     // Delete any previous laid out lines before setting the new ones.
1285     lines.Clear();
1286
1287     // The capacity of the bidirectional paragraph info is the number of paragraphs.
1288     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
1289
1290     // Resize the vector of positions to have the same size than the vector of glyphs.
1291     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1292     glyphPositions.Resize( numberOfGlyphs );
1293
1294     // Update the visual model.
1295     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1296                                                    glyphPositions,
1297                                                    lines,
1298                                                    layoutSize );
1299
1300     if( viewUpdated )
1301     {
1302       // Reorder the lines
1303       if( REORDER & operations )
1304       {
1305         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1306
1307         // Check first if there are paragraphs with bidirectional info.
1308         if( 0u != bidirectionalInfo.Count() )
1309         {
1310           // Get the lines
1311           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
1312
1313           // Reorder the lines.
1314           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1315           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1316           ReorderLines( bidirectionalInfo,
1317                         lines,
1318                         lineBidirectionalInfoRuns );
1319
1320           // Set the bidirectional info into the model.
1321           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1322           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1323                                                        numberOfBidirectionalInfoRuns );
1324
1325           // Set the bidirectional info per line into the layout parameters.
1326           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1327           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1328
1329           // Get the character to glyph conversion table and set into the layout.
1330           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1331
1332           // Get the glyphs per character table and set into the layout.
1333           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1334
1335           // Re-layout the text. Reorder those lines with right to left characters.
1336           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1337                                                          glyphPositions );
1338
1339           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1340           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1341                  endIt = lineBidirectionalInfoRuns.End();
1342                it != endIt;
1343                ++it )
1344           {
1345             BidirectionalLineInfoRun& bidiLineInfo = *it;
1346
1347             free( bidiLineInfo.visualToLogicalMap );
1348           }
1349         }
1350       } // REORDER
1351
1352       if( ALIGN & operations )
1353       {
1354         mImpl->mLayoutEngine.Align( layoutParameters,
1355                                     lines,
1356                                     glyphPositions );
1357       }
1358
1359       // Sets the actual size.
1360       if( UPDATE_ACTUAL_SIZE & operations )
1361       {
1362         mImpl->mVisualModel->SetActualSize( layoutSize );
1363       }
1364     } // view updated
1365   }
1366   else
1367   {
1368     layoutSize = mImpl->mVisualModel->GetActualSize();
1369   }
1370
1371   return viewUpdated;
1372 }
1373
1374 View& Controller::GetView()
1375 {
1376   return mImpl->mView;
1377 }
1378
1379 LayoutEngine& Controller::GetLayoutEngine()
1380 {
1381   return mImpl->mLayoutEngine;
1382 }
1383
1384 void Controller::RequestRelayout()
1385 {
1386   mImpl->mControlInterface.RequestTextRelayout();
1387 }
1388
1389 void Controller::KeyboardFocusGainEvent()
1390 {
1391   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1392
1393   if( mImpl->mTextInput )
1394   {
1395     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1396     mImpl->mTextInput->mEventQueue.push_back( event );
1397
1398     RequestRelayout();
1399   }
1400 }
1401
1402 void Controller::KeyboardFocusLostEvent()
1403 {
1404   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1405
1406   if( mImpl->mTextInput )
1407   {
1408     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1409     mImpl->mTextInput->mEventQueue.push_back( event );
1410
1411     RequestRelayout();
1412   }
1413 }
1414
1415 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1416 {
1417   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1418
1419   if( mImpl->mTextInput &&
1420       keyEvent.state == KeyEvent::Down )
1421   {
1422     int keyCode = keyEvent.keyCode;
1423     const std::string& keyString = keyEvent.keyPressed;
1424
1425     // Pre-process to separate modifying events from non-modifying input events.
1426     if( Dali::DALI_KEY_ESCAPE == keyCode )
1427     {
1428       // Escape key is a special case which causes focus loss
1429       KeyboardFocusLostEvent();
1430     }
1431     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1432              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1433              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1434              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1435     {
1436       TextInput::Event event( TextInput::CURSOR_KEY_EVENT );
1437       event.p1.mInt = keyCode;
1438       mImpl->mTextInput->mEventQueue.push_back( event );
1439     }
1440     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1441     {
1442       // Queue a delete event
1443       ModifyEvent event;
1444       event.type = DELETE_TEXT;
1445       mImpl->mModifyEvents.push_back( event );
1446     }
1447     else if( !keyString.empty() )
1448     {
1449       // Queue an insert event
1450       ModifyEvent event;
1451       event.type = INSERT_TEXT;
1452       event.text = keyString;
1453       mImpl->mModifyEvents.push_back( event );
1454     }
1455
1456     RequestRelayout();
1457   }
1458
1459   return false;
1460 }
1461
1462 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1463 {
1464   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1465
1466   if( mImpl->mTextInput )
1467   {
1468     TextInput::Event event( TextInput::TAP_EVENT );
1469     event.p1.mUint = tapCount;
1470     event.p2.mFloat = x;
1471     event.p3.mFloat = y;
1472     mImpl->mTextInput->mEventQueue.push_back( event );
1473
1474     RequestRelayout();
1475   }
1476 }
1477
1478 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1479 {
1480   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected PanEvent" );
1481
1482   if( mImpl->mTextInput )
1483   {
1484     TextInput::Event event( TextInput::PAN_EVENT );
1485     event.p1.mInt = state;
1486     event.p2.mFloat = displacement.x;
1487     event.p3.mFloat = displacement.y;
1488     mImpl->mTextInput->mEventQueue.push_back( event );
1489
1490     RequestRelayout();
1491   }
1492 }
1493
1494 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1495 {
1496   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1497
1498   if( mImpl->mTextInput )
1499   {
1500     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1501     event.p1.mUint  = state;
1502     event.p2.mFloat = x;
1503     event.p3.mFloat = y;
1504     mImpl->mTextInput->mEventQueue.push_back( event );
1505
1506     RequestRelayout();
1507   }
1508 }
1509
1510 Controller::~Controller()
1511 {
1512   delete mImpl;
1513 }
1514
1515 Controller::Controller( ControlInterface& controlInterface )
1516 : mImpl( NULL )
1517 {
1518   mImpl = new Controller::Impl( controlInterface );
1519 }
1520
1521 } // namespace Text
1522
1523 } // namespace Toolkit
1524
1525 } // namespace Dali