Respect the accessibility settings
[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   // Clear the font-specific data
682   mImpl->mLogicalModel->mFontRuns.Clear();
683   mImpl->mVisualModel->mGlyphs.Clear();
684   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
685   mImpl->mVisualModel->mCharactersToGlyph.Clear();
686   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
687   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
688   mImpl->mVisualModel->mGlyphPositions.Clear();
689   mImpl->mVisualModel->mLines.Clear();
690
691   RequestRelayout();
692 }
693
694 const std::string& Controller::GetDefaultFontFamily() const
695 {
696   if( mImpl->mFontDefaults )
697   {
698     return mImpl->mFontDefaults->mDefaultFontFamily;
699   }
700
701   return EMPTY_STRING;
702 }
703
704 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
705 {
706   if( !mImpl->mFontDefaults )
707   {
708     mImpl->mFontDefaults = new Controller::FontDefaults();
709   }
710
711   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
712   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
713   mImpl->mOperationsPending = ALL_OPERATIONS;
714   mImpl->mRecalculateNaturalSize = true;
715
716   // Clear the font-specific data
717   mImpl->mLogicalModel->mFontRuns.Clear();
718   mImpl->mVisualModel->mGlyphs.Clear();
719   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
720   mImpl->mVisualModel->mCharactersToGlyph.Clear();
721   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
722   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
723   mImpl->mVisualModel->mGlyphPositions.Clear();
724   mImpl->mVisualModel->mLines.Clear();
725
726   RequestRelayout();
727 }
728
729 const std::string& Controller::GetDefaultFontStyle() const
730 {
731   if( mImpl->mFontDefaults )
732   {
733     return mImpl->mFontDefaults->mDefaultFontStyle;
734   }
735
736   return EMPTY_STRING;
737 }
738
739 void Controller::SetDefaultPointSize( float pointSize )
740 {
741   if( !mImpl->mFontDefaults )
742   {
743     mImpl->mFontDefaults = new Controller::FontDefaults();
744   }
745
746   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
747   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
748   mImpl->mOperationsPending = ALL_OPERATIONS;
749   mImpl->mRecalculateNaturalSize = true;
750
751   // Clear the font-specific data
752   mImpl->mLogicalModel->mFontRuns.Clear();
753   mImpl->mVisualModel->mGlyphs.Clear();
754   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
755   mImpl->mVisualModel->mCharactersToGlyph.Clear();
756   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
757   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
758   mImpl->mVisualModel->mGlyphPositions.Clear();
759   mImpl->mVisualModel->mLines.Clear();
760
761   RequestRelayout();
762 }
763
764 float Controller::GetDefaultPointSize() const
765 {
766   if( mImpl->mFontDefaults )
767   {
768     return mImpl->mFontDefaults->mDefaultPointSize;
769   }
770
771   return 0.0f;
772 }
773
774 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
775 {
776   if( mImpl->mFontDefaults )
777   {
778     FontRun fontRun;
779     fontRun.characterRun.characterIndex = 0;
780     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
781     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
782     fontRun.isDefault = true;
783
784     fonts.PushBack( fontRun );
785   }
786 }
787
788 void Controller::EnableTextInput( DecoratorPtr decorator )
789 {
790   if( !mImpl->mTextInput )
791   {
792     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
793   }
794 }
795
796 void Controller::SetEnableCursorBlink( bool enable )
797 {
798   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
799
800   if( mImpl->mTextInput )
801   {
802     mImpl->mTextInput->mCursorBlinkEnabled = enable;
803
804     if( !enable &&
805         mImpl->mTextInput->mDecorator )
806     {
807       mImpl->mTextInput->mDecorator->StopCursorBlink();
808     }
809   }
810 }
811
812 bool Controller::GetEnableCursorBlink() const
813 {
814   if( mImpl->mTextInput )
815   {
816     return mImpl->mTextInput->mCursorBlinkEnabled;
817   }
818
819   return false;
820 }
821
822 const Vector2& Controller::GetScrollPosition() const
823 {
824   if( mImpl->mTextInput )
825   {
826     return mImpl->mTextInput->mScrollPosition;
827   }
828
829   return Vector2::ZERO;
830 }
831
832 const Vector2& Controller::GetAlignmentOffset() const
833 {
834   return mImpl->mAlignmentOffset;
835 }
836
837 Vector3 Controller::GetNaturalSize()
838 {
839   Vector3 naturalSize;
840
841   // Make sure the model is up-to-date before layouting
842   ProcessModifyEvents();
843
844   if( mImpl->mRecalculateNaturalSize )
845   {
846     // Operations that can be done only once until the text changes.
847     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
848                                                                            GET_SCRIPTS       |
849                                                                            VALIDATE_FONTS    |
850                                                                            GET_LINE_BREAKS   |
851                                                                            GET_WORD_BREAKS   |
852                                                                            BIDI_INFO         |
853                                                                            SHAPE_TEXT        |
854                                                                            GET_GLYPH_METRICS );
855     // Make sure the model is up-to-date before layouting
856     UpdateModel( onlyOnceOperations );
857
858     // Operations that need to be done if the size changes.
859     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
860                                                                         ALIGN  |
861                                                                         REORDER );
862
863     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
864                 static_cast<OperationsMask>( onlyOnceOperations |
865                                              sizeOperations ),
866                 naturalSize.GetVectorXY() );
867
868     // Do not do again the only once operations.
869     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
870
871     // Do the size related operations again.
872     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
873
874     // Stores the natural size to avoid recalculate it again
875     // unless the text/style changes.
876     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
877
878     mImpl->mRecalculateNaturalSize = false;
879   }
880   else
881   {
882     naturalSize = mImpl->mVisualModel->GetNaturalSize();
883   }
884
885   return naturalSize;
886 }
887
888 float Controller::GetHeightForWidth( float width )
889 {
890   // Make sure the model is up-to-date before layouting
891   ProcessModifyEvents();
892
893   Size layoutSize;
894   if( width != mImpl->mControlSize.width )
895   {
896     // Operations that can be done only once until the text changes.
897     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
898                                                                            GET_SCRIPTS       |
899                                                                            VALIDATE_FONTS    |
900                                                                            GET_LINE_BREAKS   |
901                                                                            GET_WORD_BREAKS   |
902                                                                            BIDI_INFO         |
903                                                                            SHAPE_TEXT        |
904                                                                            GET_GLYPH_METRICS );
905     // Make sure the model is up-to-date before layouting
906     UpdateModel( onlyOnceOperations );
907
908     // Operations that need to be done if the size changes.
909     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
910                                                                         ALIGN  |
911                                                                         REORDER );
912
913     DoRelayout( Size( width, MAX_FLOAT ),
914                 static_cast<OperationsMask>( onlyOnceOperations |
915                                              sizeOperations ),
916                 layoutSize );
917
918     // Do not do again the only once operations.
919     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
920
921     // Do the size related operations again.
922     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
923   }
924   else
925   {
926     layoutSize = mImpl->mVisualModel->GetActualSize();
927   }
928
929   return layoutSize.height;
930 }
931
932 bool Controller::Relayout( const Size& size )
933 {
934   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
935   {
936     bool glyphsRemoved( false );
937     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
938     {
939       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
940       glyphsRemoved = true;
941     }
942
943     // Not worth to relayout if width or height is equal to zero.
944     return glyphsRemoved;
945   }
946
947   if( size != mImpl->mControlSize )
948   {
949     // Operations that need to be done if the size changes.
950     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
951                                                              LAYOUT                    |
952                                                              ALIGN                     |
953                                                              UPDATE_ACTUAL_SIZE        |
954                                                              REORDER );
955
956     mImpl->mControlSize = size;
957   }
958
959   // Make sure the model is up-to-date before layouting
960   ProcessModifyEvents();
961   UpdateModel( mImpl->mOperationsPending );
962
963   Size layoutSize;
964   bool updated = DoRelayout( mImpl->mControlSize,
965                              mImpl->mOperationsPending,
966                              layoutSize );
967
968   // Do not re-do any operation until something changes.
969   mImpl->mOperationsPending = NO_OPERATION;
970
971   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
972   CalculateTextAlignment( size );
973
974   if( mImpl->mTextInput )
975   {
976     // Move the cursor, grab handle etc.
977     updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize, mImpl->mAlignmentOffset ) || updated;
978   }
979
980   return updated;
981 }
982
983 void Controller::ProcessModifyEvents()
984 {
985   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
986
987   for( unsigned int i=0; i<events.size(); ++i )
988   {
989     if( REPLACE_TEXT == events[0].type )
990     {
991       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
992       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
993
994       ReplaceTextEvent( events[0].text );
995     }
996     else if( INSERT_TEXT == events[0].type )
997     {
998       InsertTextEvent( events[0].text );
999     }
1000     else if( DELETE_TEXT == events[0].type )
1001     {
1002       DeleteTextEvent();
1003     }
1004   }
1005
1006   // Discard temporary text
1007   events.clear();
1008 }
1009
1010 void Controller::ReplaceTextEvent( const std::string& text )
1011 {
1012   // Reset buffers.
1013   mImpl->mLogicalModel->mText.Clear();
1014   mImpl->mLogicalModel->mScriptRuns.Clear();
1015   mImpl->mLogicalModel->mFontRuns.Clear();
1016   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1017   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1018   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1019   mImpl->mLogicalModel->mCharacterDirections.Clear();
1020   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1021   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1022   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1023   mImpl->mVisualModel->mGlyphs.Clear();
1024   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1025   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1026   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1027   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1028   mImpl->mVisualModel->mGlyphPositions.Clear();
1029   mImpl->mVisualModel->mLines.Clear();
1030
1031   //  Convert text into UTF-32
1032   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1033   utf32Characters.Resize( text.size() );
1034
1035   // This is a bit horrible but std::string returns a (signed) char*
1036   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1037
1038   // Transform a text array encoded in utf8 into an array encoded in utf32.
1039   // It returns the actual number of characters.
1040   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1041   utf32Characters.Resize( characterCount );
1042
1043   // Reset the cursor position
1044   if( mImpl->mTextInput )
1045   {
1046     mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
1047     // TODO - handle secondary cursor
1048   }
1049
1050   // The natural size needs to be re-calculated.
1051   mImpl->mRecalculateNaturalSize = true;
1052
1053   // Apply modifications to the model
1054   mImpl->mOperationsPending = ALL_OPERATIONS;
1055   UpdateModel( ALL_OPERATIONS );
1056   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1057                                                            ALIGN              |
1058                                                            UPDATE_ACTUAL_SIZE |
1059                                                            REORDER );
1060 }
1061
1062 void Controller::InsertTextEvent( const std::string& text )
1063 {
1064   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1065
1066   // TODO - Optimize this
1067   mImpl->mLogicalModel->mScriptRuns.Clear();
1068   mImpl->mLogicalModel->mFontRuns.Clear();
1069   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1070   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1071   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1072   mImpl->mLogicalModel->mCharacterDirections.Clear();
1073   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1074   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1075   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1076   mImpl->mVisualModel->mGlyphs.Clear();
1077   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1078   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1079   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1080   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1081   mImpl->mVisualModel->mGlyphPositions.Clear();
1082   mImpl->mVisualModel->mLines.Clear();
1083
1084   //  Convert text into UTF-32
1085   Vector<Character> utf32Characters;
1086   utf32Characters.Resize( text.size() );
1087
1088   // This is a bit horrible but std::string returns a (signed) char*
1089   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1090
1091   // Transform a text array encoded in utf8 into an array encoded in utf32.
1092   // It returns the actual number of characters.
1093   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1094   utf32Characters.Resize( characterCount );
1095
1096   // Insert at current cursor position
1097   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1098   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1099
1100   if( cursorIndex < modifyText.Count() )
1101   {
1102     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
1103   }
1104   else
1105   {
1106     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
1107   }
1108
1109   // Advance the cursor position
1110   ++cursorIndex;
1111
1112   // The natural size needs to be re-calculated.
1113   mImpl->mRecalculateNaturalSize = true;
1114
1115   // Apply modifications to the model; TODO - Optimize this
1116   mImpl->mOperationsPending = ALL_OPERATIONS;
1117   UpdateModel( ALL_OPERATIONS );
1118   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1119                                                            ALIGN              |
1120                                                            UPDATE_ACTUAL_SIZE |
1121                                                            REORDER );
1122
1123   // Queue a cursor reposition event; this must wait until after DoRelayout()
1124   mImpl->mTextInput->mUpdateCursorPosition = true;
1125 }
1126
1127 void Controller::DeleteTextEvent()
1128 {
1129   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1130
1131   // TODO - Optimize this
1132   mImpl->mLogicalModel->mScriptRuns.Clear();
1133   mImpl->mLogicalModel->mFontRuns.Clear();
1134   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1135   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1136   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1137   mImpl->mLogicalModel->mCharacterDirections.Clear();
1138   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1139   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1140   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1141   mImpl->mVisualModel->mGlyphs.Clear();
1142   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1143   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1144   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1145   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1146   mImpl->mVisualModel->mGlyphPositions.Clear();
1147   mImpl->mVisualModel->mLines.Clear();
1148
1149   // Delte at current cursor position
1150   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1151   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1152
1153   if( cursorIndex > 0 &&
1154       cursorIndex-1 < modifyText.Count() )
1155   {
1156     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
1157
1158     // Cursor position retreat
1159     --cursorIndex;
1160   }
1161
1162   // The natural size needs to be re-calculated.
1163   mImpl->mRecalculateNaturalSize = true;
1164
1165   // Apply modifications to the model; TODO - Optimize this
1166   mImpl->mOperationsPending = ALL_OPERATIONS;
1167   UpdateModel( ALL_OPERATIONS );
1168   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1169                                                            ALIGN              |
1170                                                            UPDATE_ACTUAL_SIZE |
1171                                                            REORDER );
1172
1173   // Queue a cursor reposition event; this must wait until after DoRelayout()
1174   mImpl->mTextInput->mUpdateCursorPosition = true;
1175 }
1176
1177 void Controller::UpdateModel( OperationsMask operationsRequired )
1178 {
1179   // Calculate the operations to be done.
1180   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1181
1182   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1183
1184   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
1185
1186   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1187   if( GET_LINE_BREAKS & operations )
1188   {
1189     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
1190     // calculate the bidirectional info for each 'paragraph'.
1191     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
1192     // is not shaped together).
1193     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
1194
1195     SetLineBreakInfo( utf32Characters,
1196                       lineBreakInfo );
1197   }
1198
1199   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1200   if( GET_WORD_BREAKS & operations )
1201   {
1202     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
1203     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
1204
1205     SetWordBreakInfo( utf32Characters,
1206                       wordBreakInfo );
1207   }
1208
1209   const bool getScripts = GET_SCRIPTS & operations;
1210   const bool validateFonts = VALIDATE_FONTS & operations;
1211
1212   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
1213   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
1214
1215   if( getScripts || validateFonts )
1216   {
1217     // Validates the fonts assigned by the application or assigns default ones.
1218     // It makes sure all the characters are going to be rendered by the correct font.
1219     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
1220
1221     if( getScripts )
1222     {
1223       // Retrieves the scripts used in the text.
1224       multilanguageSupport.SetScripts( utf32Characters,
1225                                        lineBreakInfo,
1226                                        scripts );
1227     }
1228
1229     if( validateFonts )
1230     {
1231       if( 0u == validFonts.Count() )
1232       {
1233         // Copy the requested font defaults received via the property system.
1234         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
1235         GetDefaultFonts( validFonts, numberOfCharacters );
1236       }
1237
1238       // Validates the fonts. If there is a character with no assigned font it sets a default one.
1239       // After this call, fonts are validated.
1240       multilanguageSupport.ValidateFonts( utf32Characters,
1241                                           scripts,
1242                                           validFonts );
1243     }
1244   }
1245
1246   Vector<Character> mirroredUtf32Characters;
1247   bool textMirrored = false;
1248   if( BIDI_INFO & operations )
1249   {
1250     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
1251     // bidirectional info.
1252
1253     Length numberOfParagraphs = 0u;
1254
1255     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
1256     for( Length index = 0u; index < numberOfCharacters; ++index )
1257     {
1258       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
1259       {
1260         ++numberOfParagraphs;
1261       }
1262     }
1263
1264     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1265     bidirectionalInfo.Reserve( numberOfParagraphs );
1266
1267     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1268     SetBidirectionalInfo( utf32Characters,
1269                           scripts,
1270                           lineBreakInfo,
1271                           bidirectionalInfo );
1272
1273     if( 0u != bidirectionalInfo.Count() )
1274     {
1275       // This paragraph has right to left text. Some characters may need to be mirrored.
1276       // TODO: consider if the mirrored string can be stored as well.
1277
1278       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
1279
1280       // Only set the character directions if there is right to left characters.
1281       Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
1282       directions.Resize( numberOfCharacters );
1283
1284       GetCharactersDirection( bidirectionalInfo,
1285                               directions );
1286     }
1287     else
1288     {
1289       // There is no right to left characters. Clear the directions vector.
1290       mImpl->mLogicalModel->mCharacterDirections.Clear();
1291     }
1292
1293    }
1294
1295   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1296   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1297   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1298   if( SHAPE_TEXT & operations )
1299   {
1300     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1301     // Shapes the text.
1302     ShapeText( textToShape,
1303                lineBreakInfo,
1304                scripts,
1305                validFonts,
1306                glyphs,
1307                glyphsToCharactersMap,
1308                charactersPerGlyph );
1309   }
1310
1311   const Length numberOfGlyphs = glyphs.Count();
1312
1313   if( GET_GLYPH_METRICS & operations )
1314   {
1315     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
1316   }
1317
1318   if( 0u != numberOfGlyphs )
1319   {
1320     // Create the glyph to character conversion table and the 'number of glyphs' per character.
1321     mImpl->mVisualModel->CreateCharacterToGlyphTable(numberOfCharacters );
1322     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
1323   }
1324 }
1325
1326 bool Controller::DoRelayout( const Size& size,
1327                              OperationsMask operationsRequired,
1328                              Size& layoutSize )
1329 {
1330   bool viewUpdated( false );
1331
1332   // Calculate the operations to be done.
1333   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1334
1335   if( LAYOUT & operations )
1336   {
1337     // Some vectors with data needed to layout and reorder may be void
1338     // after the first time the text has been laid out.
1339     // Fill the vectors again.
1340
1341     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
1342
1343     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1344     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1345     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1346     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1347     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1348
1349     // Set the layout parameters.
1350     LayoutParameters layoutParameters( size,
1351                                        mImpl->mLogicalModel->mText.Begin(),
1352                                        lineBreakInfo.Begin(),
1353                                        wordBreakInfo.Begin(),
1354                                        numberOfGlyphs,
1355                                        glyphs.Begin(),
1356                                        glyphsToCharactersMap.Begin(),
1357                                        charactersPerGlyph.Begin() );
1358
1359     // The laid-out lines.
1360     // It's not possible to know in how many lines the text is going to be laid-out,
1361     // but it can be resized at least with the number of 'paragraphs' to avoid
1362     // some re-allocations.
1363     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1364
1365     // Delete any previous laid out lines before setting the new ones.
1366     lines.Clear();
1367
1368     // The capacity of the bidirectional paragraph info is the number of paragraphs.
1369     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
1370
1371     // Resize the vector of positions to have the same size than the vector of glyphs.
1372     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1373     glyphPositions.Resize( numberOfGlyphs );
1374
1375     // Update the visual model.
1376     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1377                                                    glyphPositions,
1378                                                    lines,
1379                                                    layoutSize );
1380
1381     if( viewUpdated )
1382     {
1383       // Reorder the lines
1384       if( REORDER & operations )
1385       {
1386         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1387
1388         // Check first if there are paragraphs with bidirectional info.
1389         if( 0u != bidirectionalInfo.Count() )
1390         {
1391           // Get the lines
1392           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
1393
1394           // Reorder the lines.
1395           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1396           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1397           ReorderLines( bidirectionalInfo,
1398                         lines,
1399                         lineBidirectionalInfoRuns );
1400
1401           // Set the bidirectional info into the model.
1402           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1403           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1404                                                        numberOfBidirectionalInfoRuns );
1405
1406           // Set the bidirectional info per line into the layout parameters.
1407           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1408           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1409
1410           // Get the character to glyph conversion table and set into the layout.
1411           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1412
1413           // Get the glyphs per character table and set into the layout.
1414           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1415
1416           // Re-layout the text. Reorder those lines with right to left characters.
1417           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1418                                                          glyphPositions );
1419
1420           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1421           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1422                  endIt = lineBidirectionalInfoRuns.End();
1423                it != endIt;
1424                ++it )
1425           {
1426             BidirectionalLineInfoRun& bidiLineInfo = *it;
1427
1428             free( bidiLineInfo.visualToLogicalMap );
1429           }
1430         }
1431       } // REORDER
1432
1433       if( ALIGN & operations )
1434       {
1435         mImpl->mLayoutEngine.Align( layoutParameters,
1436                                     layoutSize,
1437                                     lines,
1438                                     glyphPositions );
1439       }
1440
1441       // Sets the actual size.
1442       if( UPDATE_ACTUAL_SIZE & operations )
1443       {
1444         mImpl->mVisualModel->SetActualSize( layoutSize );
1445       }
1446     } // view updated
1447   }
1448   else
1449   {
1450     layoutSize = mImpl->mVisualModel->GetActualSize();
1451   }
1452
1453   return viewUpdated;
1454 }
1455
1456 void Controller::CalculateTextAlignment( const Size& size )
1457 {
1458   // TODO : Calculate the vertical offset.
1459
1460   // Get the direction of the first character.
1461   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
1462
1463   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
1464
1465   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
1466   LayoutEngine::Alignment alignment = mImpl->mLayoutEngine.GetAlignment();
1467   if( firstParagraphDirection &&
1468       ( LayoutEngine::ALIGN_CENTER != alignment ) )
1469   {
1470     if( LayoutEngine::ALIGN_BEGIN == alignment )
1471     {
1472       alignment = LayoutEngine::ALIGN_END;
1473     }
1474     else
1475     {
1476       alignment = LayoutEngine::ALIGN_BEGIN;
1477     }
1478   }
1479
1480   switch( alignment )
1481   {
1482     case LayoutEngine::ALIGN_BEGIN:
1483     {
1484       mImpl->mAlignmentOffset = Vector2::ZERO;
1485       break;
1486     }
1487     case LayoutEngine::ALIGN_CENTER:
1488     {
1489       mImpl->mAlignmentOffset.y = 0.f;
1490       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1491       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
1492       break;
1493     }
1494     case LayoutEngine::ALIGN_END:
1495     {
1496       mImpl->mAlignmentOffset.y = 0.f;
1497       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1498       break;
1499     }
1500   }
1501 }
1502
1503 View& Controller::GetView()
1504 {
1505   return mImpl->mView;
1506 }
1507
1508 LayoutEngine& Controller::GetLayoutEngine()
1509 {
1510   return mImpl->mLayoutEngine;
1511 }
1512
1513 void Controller::RequestRelayout()
1514 {
1515   mImpl->mControlInterface.RequestTextRelayout();
1516 }
1517
1518 void Controller::KeyboardFocusGainEvent()
1519 {
1520   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1521
1522   if( mImpl->mTextInput )
1523   {
1524     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1525     mImpl->mTextInput->mEventQueue.push_back( event );
1526
1527     RequestRelayout();
1528   }
1529 }
1530
1531 void Controller::KeyboardFocusLostEvent()
1532 {
1533   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1534
1535   if( mImpl->mTextInput )
1536   {
1537     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1538     mImpl->mTextInput->mEventQueue.push_back( event );
1539
1540     RequestRelayout();
1541   }
1542 }
1543
1544 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1545 {
1546   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1547
1548   if( mImpl->mTextInput &&
1549       keyEvent.state == KeyEvent::Down )
1550   {
1551     int keyCode = keyEvent.keyCode;
1552     const std::string& keyString = keyEvent.keyPressed;
1553
1554     // Pre-process to separate modifying events from non-modifying input events.
1555     if( Dali::DALI_KEY_ESCAPE == keyCode )
1556     {
1557       // Escape key is a special case which causes focus loss
1558       KeyboardFocusLostEvent();
1559     }
1560     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1561              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1562              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1563              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1564     {
1565       TextInput::Event event( TextInput::CURSOR_KEY_EVENT );
1566       event.p1.mInt = keyCode;
1567       mImpl->mTextInput->mEventQueue.push_back( event );
1568     }
1569     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1570     {
1571       // Queue a delete event
1572       ModifyEvent event;
1573       event.type = DELETE_TEXT;
1574       mImpl->mModifyEvents.push_back( event );
1575     }
1576     else if( !keyString.empty() )
1577     {
1578       // Queue an insert event
1579       ModifyEvent event;
1580       event.type = INSERT_TEXT;
1581       event.text = keyString;
1582       mImpl->mModifyEvents.push_back( event );
1583     }
1584
1585     RequestRelayout();
1586   }
1587
1588   return false;
1589 }
1590
1591 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1592 {
1593   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1594
1595   if( mImpl->mTextInput )
1596   {
1597     TextInput::Event event( TextInput::TAP_EVENT );
1598     event.p1.mUint = tapCount;
1599     event.p2.mFloat = x;
1600     event.p3.mFloat = y;
1601     mImpl->mTextInput->mEventQueue.push_back( event );
1602
1603     RequestRelayout();
1604   }
1605 }
1606
1607 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1608 {
1609   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected PanEvent" );
1610
1611   if( mImpl->mTextInput )
1612   {
1613     TextInput::Event event( TextInput::PAN_EVENT );
1614     event.p1.mInt = state;
1615     event.p2.mFloat = displacement.x;
1616     event.p3.mFloat = displacement.y;
1617     mImpl->mTextInput->mEventQueue.push_back( event );
1618
1619     RequestRelayout();
1620   }
1621 }
1622
1623 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1624 {
1625   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1626
1627   if( mImpl->mTextInput )
1628   {
1629     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1630     event.p1.mUint  = state;
1631     event.p2.mFloat = x;
1632     event.p3.mFloat = y;
1633     mImpl->mTextInput->mEventQueue.push_back( event );
1634
1635     RequestRelayout();
1636   }
1637 }
1638
1639 Controller::~Controller()
1640 {
1641   delete mImpl;
1642 }
1643
1644 Controller::Controller( ControlInterface& controlInterface )
1645 : mImpl( NULL )
1646 {
1647   mImpl = new Controller::Impl( controlInterface );
1648 }
1649
1650 } // namespace Text
1651
1652 } // namespace Toolkit
1653
1654 } // namespace Dali