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