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