Merge "Added metrics logging to TextAtlasRenderer" 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->mCharacterDirections.Clear();
955   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
956   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
957   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
958   mImpl->mVisualModel->mGlyphs.Clear();
959   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
960   mImpl->mVisualModel->mCharactersToGlyph.Clear();
961   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
962   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
963   mImpl->mVisualModel->mGlyphPositions.Clear();
964   mImpl->mVisualModel->mLines.Clear();
965
966   //  Convert text into UTF-32
967   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
968   utf32Characters.Resize( text.size() );
969
970   // This is a bit horrible but std::string returns a (signed) char*
971   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
972
973   // Transform a text array encoded in utf8 into an array encoded in utf32.
974   // It returns the actual number of characters.
975   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
976   utf32Characters.Resize( characterCount );
977
978   // Reset the cursor position
979   if( mImpl->mTextInput )
980   {
981     mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
982     // TODO - handle secondary cursor
983   }
984
985   // The natural size needs to be re-calculated.
986   mImpl->mRecalculateNaturalSize = true;
987
988   // Apply modifications to the model
989   mImpl->mOperationsPending = ALL_OPERATIONS;
990   UpdateModel( ALL_OPERATIONS );
991   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
992                                                            ALIGN              |
993                                                            UPDATE_ACTUAL_SIZE |
994                                                            REORDER );
995 }
996
997 void Controller::InsertTextEvent( const std::string& text )
998 {
999   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1000
1001   // TODO - Optimize this
1002   mImpl->mLogicalModel->mScriptRuns.Clear();
1003   mImpl->mLogicalModel->mFontRuns.Clear();
1004   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1005   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1006   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1007   mImpl->mLogicalModel->mCharacterDirections.Clear();
1008   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1009   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1010   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1011   mImpl->mVisualModel->mGlyphs.Clear();
1012   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1013   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1014   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1015   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1016   mImpl->mVisualModel->mGlyphPositions.Clear();
1017   mImpl->mVisualModel->mLines.Clear();
1018
1019   //  Convert text into UTF-32
1020   Vector<Character> utf32Characters;
1021   utf32Characters.Resize( text.size() );
1022
1023   // This is a bit horrible but std::string returns a (signed) char*
1024   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1025
1026   // Transform a text array encoded in utf8 into an array encoded in utf32.
1027   // It returns the actual number of characters.
1028   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1029   utf32Characters.Resize( characterCount );
1030
1031   // Insert at current cursor position
1032   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1033   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1034
1035   if( cursorIndex < modifyText.Count() )
1036   {
1037     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
1038   }
1039   else
1040   {
1041     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
1042   }
1043
1044   // Advance the cursor position
1045   ++cursorIndex;
1046
1047   // The natural size needs to be re-calculated.
1048   mImpl->mRecalculateNaturalSize = true;
1049
1050   // Apply modifications to the model; TODO - Optimize this
1051   mImpl->mOperationsPending = ALL_OPERATIONS;
1052   UpdateModel( ALL_OPERATIONS );
1053   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1054                                                            ALIGN              |
1055                                                            UPDATE_ACTUAL_SIZE |
1056                                                            REORDER );
1057
1058   // Queue a cursor reposition event; this must wait until after DoRelayout()
1059   mImpl->mTextInput->mUpdateCursorPosition = true;
1060 }
1061
1062 void Controller::DeleteTextEvent()
1063 {
1064   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1065
1066   // TODO - Optimize this
1067   mImpl->mLogicalModel->mScriptRuns.Clear();
1068   mImpl->mLogicalModel->mFontRuns.Clear();
1069   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1070   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1071   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1072   mImpl->mLogicalModel->mCharacterDirections.Clear();
1073   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1074   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1075   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1076   mImpl->mVisualModel->mGlyphs.Clear();
1077   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1078   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1079   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1080   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1081   mImpl->mVisualModel->mGlyphPositions.Clear();
1082   mImpl->mVisualModel->mLines.Clear();
1083
1084   // Delte at current cursor position
1085   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1086   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1087
1088   if( cursorIndex > 0 &&
1089       cursorIndex-1 < modifyText.Count() )
1090   {
1091     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
1092
1093     // Cursor position retreat
1094     --cursorIndex;
1095   }
1096
1097   // The natural size needs to be re-calculated.
1098   mImpl->mRecalculateNaturalSize = true;
1099
1100   // Apply modifications to the model; TODO - Optimize this
1101   mImpl->mOperationsPending = ALL_OPERATIONS;
1102   UpdateModel( ALL_OPERATIONS );
1103   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1104                                                            ALIGN              |
1105                                                            UPDATE_ACTUAL_SIZE |
1106                                                            REORDER );
1107
1108   // Queue a cursor reposition event; this must wait until after DoRelayout()
1109   mImpl->mTextInput->mUpdateCursorPosition = true;
1110 }
1111
1112 void Controller::UpdateModel( OperationsMask operationsRequired )
1113 {
1114   // Calculate the operations to be done.
1115   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1116
1117   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1118
1119   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
1120
1121   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1122   if( GET_LINE_BREAKS & operations )
1123   {
1124     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
1125     // calculate the bidirectional info for each 'paragraph'.
1126     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
1127     // is not shaped together).
1128     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
1129
1130     SetLineBreakInfo( utf32Characters,
1131                       lineBreakInfo );
1132   }
1133
1134   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1135   if( GET_WORD_BREAKS & operations )
1136   {
1137     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
1138     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
1139
1140     SetWordBreakInfo( utf32Characters,
1141                       wordBreakInfo );
1142   }
1143
1144   const bool getScripts = GET_SCRIPTS & operations;
1145   const bool validateFonts = VALIDATE_FONTS & operations;
1146
1147   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
1148   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
1149
1150   if( getScripts || validateFonts )
1151   {
1152     // Validates the fonts assigned by the application or assigns default ones.
1153     // It makes sure all the characters are going to be rendered by the correct font.
1154     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
1155
1156     if( getScripts )
1157     {
1158       // Retrieves the scripts used in the text.
1159       multilanguageSupport.SetScripts( utf32Characters,
1160                                        lineBreakInfo,
1161                                        scripts );
1162     }
1163
1164     if( validateFonts )
1165     {
1166       if( 0u == validFonts.Count() )
1167       {
1168         // Copy the requested font defaults received via the property system.
1169         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
1170         GetDefaultFonts( validFonts, numberOfCharacters );
1171       }
1172
1173       // Validates the fonts. If there is a character with no assigned font it sets a default one.
1174       // After this call, fonts are validated.
1175       multilanguageSupport.ValidateFonts( utf32Characters,
1176                                           scripts,
1177                                           validFonts );
1178     }
1179   }
1180
1181   Vector<Character> mirroredUtf32Characters;
1182   bool textMirrored = false;
1183   if( BIDI_INFO & operations )
1184   {
1185     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
1186     // bidirectional info.
1187
1188     Length numberOfParagraphs = 0u;
1189
1190     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
1191     for( Length index = 0u; index < numberOfCharacters; ++index )
1192     {
1193       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
1194       {
1195         ++numberOfParagraphs;
1196       }
1197     }
1198
1199     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1200     bidirectionalInfo.Reserve( numberOfParagraphs );
1201
1202     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1203     SetBidirectionalInfo( utf32Characters,
1204                           scripts,
1205                           lineBreakInfo,
1206                           bidirectionalInfo );
1207
1208     if( 0u != bidirectionalInfo.Count() )
1209     {
1210       // This paragraph has right to left text. Some characters may need to be mirrored.
1211       // TODO: consider if the mirrored string can be stored as well.
1212
1213       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
1214
1215       // Only set the character directions if there is right to left characters.
1216       Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
1217       directions.Resize( numberOfCharacters );
1218
1219       GetCharactersDirection( bidirectionalInfo,
1220                               directions );
1221     }
1222     else
1223     {
1224       // There is no right to left characters. Clear the directions vector.
1225       mImpl->mLogicalModel->mCharacterDirections.Clear();
1226     }
1227
1228    }
1229
1230   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1231   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1232   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1233   if( SHAPE_TEXT & operations )
1234   {
1235     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1236     // Shapes the text.
1237     ShapeText( textToShape,
1238                lineBreakInfo,
1239                scripts,
1240                validFonts,
1241                glyphs,
1242                glyphsToCharactersMap,
1243                charactersPerGlyph );
1244   }
1245
1246   const Length numberOfGlyphs = glyphs.Count();
1247
1248   if( GET_GLYPH_METRICS & operations )
1249   {
1250     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
1251   }
1252
1253   if( 0u != numberOfGlyphs )
1254   {
1255     // Create the glyph to character conversion table and the 'number of glyphs' per character.
1256     mImpl->mVisualModel->CreateCharacterToGlyphTable(numberOfCharacters );
1257     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
1258   }
1259 }
1260
1261 bool Controller::DoRelayout( const Vector2& size,
1262                              OperationsMask operationsRequired,
1263                              Size& layoutSize )
1264 {
1265   bool viewUpdated( false );
1266
1267   // Calculate the operations to be done.
1268   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1269
1270   if( LAYOUT & operations )
1271   {
1272     // Some vectors with data needed to layout and reorder may be void
1273     // after the first time the text has been laid out.
1274     // Fill the vectors again.
1275
1276     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
1277
1278     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1279     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1280     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1281     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1282     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1283
1284     // Set the layout parameters.
1285     LayoutParameters layoutParameters( size,
1286                                        mImpl->mLogicalModel->mText.Begin(),
1287                                        lineBreakInfo.Begin(),
1288                                        wordBreakInfo.Begin(),
1289                                        numberOfGlyphs,
1290                                        glyphs.Begin(),
1291                                        glyphsToCharactersMap.Begin(),
1292                                        charactersPerGlyph.Begin() );
1293
1294     // The laid-out lines.
1295     // It's not possible to know in how many lines the text is going to be laid-out,
1296     // but it can be resized at least with the number of 'paragraphs' to avoid
1297     // some re-allocations.
1298     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1299
1300     // Delete any previous laid out lines before setting the new ones.
1301     lines.Clear();
1302
1303     // The capacity of the bidirectional paragraph info is the number of paragraphs.
1304     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
1305
1306     // Resize the vector of positions to have the same size than the vector of glyphs.
1307     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1308     glyphPositions.Resize( numberOfGlyphs );
1309
1310     // Update the visual model.
1311     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1312                                                    glyphPositions,
1313                                                    lines,
1314                                                    layoutSize );
1315
1316     if( viewUpdated )
1317     {
1318       // Reorder the lines
1319       if( REORDER & operations )
1320       {
1321         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1322
1323         // Check first if there are paragraphs with bidirectional info.
1324         if( 0u != bidirectionalInfo.Count() )
1325         {
1326           // Get the lines
1327           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
1328
1329           // Reorder the lines.
1330           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1331           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1332           ReorderLines( bidirectionalInfo,
1333                         lines,
1334                         lineBidirectionalInfoRuns );
1335
1336           // Set the bidirectional info into the model.
1337           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1338           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1339                                                        numberOfBidirectionalInfoRuns );
1340
1341           // Set the bidirectional info per line into the layout parameters.
1342           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1343           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1344
1345           // Get the character to glyph conversion table and set into the layout.
1346           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1347
1348           // Get the glyphs per character table and set into the layout.
1349           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1350
1351           // Re-layout the text. Reorder those lines with right to left characters.
1352           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1353                                                          glyphPositions );
1354
1355           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1356           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1357                  endIt = lineBidirectionalInfoRuns.End();
1358                it != endIt;
1359                ++it )
1360           {
1361             BidirectionalLineInfoRun& bidiLineInfo = *it;
1362
1363             free( bidiLineInfo.visualToLogicalMap );
1364           }
1365         }
1366       } // REORDER
1367
1368       if( ALIGN & operations )
1369       {
1370         mImpl->mLayoutEngine.Align( layoutParameters,
1371                                     lines,
1372                                     glyphPositions );
1373       }
1374
1375       // Sets the actual size.
1376       if( UPDATE_ACTUAL_SIZE & operations )
1377       {
1378         mImpl->mVisualModel->SetActualSize( layoutSize );
1379       }
1380     } // view updated
1381   }
1382   else
1383   {
1384     layoutSize = mImpl->mVisualModel->GetActualSize();
1385   }
1386
1387   return viewUpdated;
1388 }
1389
1390 View& Controller::GetView()
1391 {
1392   return mImpl->mView;
1393 }
1394
1395 LayoutEngine& Controller::GetLayoutEngine()
1396 {
1397   return mImpl->mLayoutEngine;
1398 }
1399
1400 void Controller::RequestRelayout()
1401 {
1402   mImpl->mControlInterface.RequestTextRelayout();
1403 }
1404
1405 void Controller::KeyboardFocusGainEvent()
1406 {
1407   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1408
1409   if( mImpl->mTextInput )
1410   {
1411     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1412     mImpl->mTextInput->mEventQueue.push_back( event );
1413
1414     RequestRelayout();
1415   }
1416 }
1417
1418 void Controller::KeyboardFocusLostEvent()
1419 {
1420   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1421
1422   if( mImpl->mTextInput )
1423   {
1424     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1425     mImpl->mTextInput->mEventQueue.push_back( event );
1426
1427     RequestRelayout();
1428   }
1429 }
1430
1431 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1432 {
1433   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1434
1435   if( mImpl->mTextInput &&
1436       keyEvent.state == KeyEvent::Down )
1437   {
1438     int keyCode = keyEvent.keyCode;
1439     const std::string& keyString = keyEvent.keyPressed;
1440
1441     // Pre-process to separate modifying events from non-modifying input events.
1442     if( Dali::DALI_KEY_ESCAPE == keyCode )
1443     {
1444       // Escape key is a special case which causes focus loss
1445       KeyboardFocusLostEvent();
1446     }
1447     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1448              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1449              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1450              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1451     {
1452       TextInput::Event event( TextInput::CURSOR_KEY_EVENT );
1453       event.p1.mInt = keyCode;
1454       mImpl->mTextInput->mEventQueue.push_back( event );
1455     }
1456     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1457     {
1458       // Queue a delete event
1459       ModifyEvent event;
1460       event.type = DELETE_TEXT;
1461       mImpl->mModifyEvents.push_back( event );
1462     }
1463     else if( !keyString.empty() )
1464     {
1465       // Queue an insert event
1466       ModifyEvent event;
1467       event.type = INSERT_TEXT;
1468       event.text = keyString;
1469       mImpl->mModifyEvents.push_back( event );
1470     }
1471
1472     RequestRelayout();
1473   }
1474
1475   return false;
1476 }
1477
1478 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1479 {
1480   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1481
1482   if( mImpl->mTextInput )
1483   {
1484     TextInput::Event event( TextInput::TAP_EVENT );
1485     event.p1.mUint = tapCount;
1486     event.p2.mFloat = x;
1487     event.p3.mFloat = y;
1488     mImpl->mTextInput->mEventQueue.push_back( event );
1489
1490     RequestRelayout();
1491   }
1492 }
1493
1494 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1495 {
1496   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected PanEvent" );
1497
1498   if( mImpl->mTextInput )
1499   {
1500     TextInput::Event event( TextInput::PAN_EVENT );
1501     event.p1.mInt = state;
1502     event.p2.mFloat = displacement.x;
1503     event.p3.mFloat = displacement.y;
1504     mImpl->mTextInput->mEventQueue.push_back( event );
1505
1506     RequestRelayout();
1507   }
1508 }
1509
1510 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1511 {
1512   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1513
1514   if( mImpl->mTextInput )
1515   {
1516     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1517     event.p1.mUint  = state;
1518     event.p2.mFloat = x;
1519     event.p3.mFloat = y;
1520     mImpl->mTextInput->mEventQueue.push_back( event );
1521
1522     RequestRelayout();
1523   }
1524 }
1525
1526 Controller::~Controller()
1527 {
1528   delete mImpl;
1529 }
1530
1531 Controller::Controller( ControlInterface& controlInterface )
1532 : mImpl( NULL )
1533 {
1534   mImpl = new Controller::Impl( controlInterface );
1535 }
1536
1537 } // namespace Text
1538
1539 } // namespace Toolkit
1540
1541 } // namespace Dali