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