Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <vector>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/public-api/text-abstraction/font-client.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/logical-model-impl.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/script-run.h>
35 #include <dali-toolkit/internal/text/segmentation.h>
36 #include <dali-toolkit/internal/text/shaper.h>
37 #include <dali-toolkit/internal/text/text-io.h>
38 #include <dali-toolkit/internal/text/text-view.h>
39 #include <dali-toolkit/internal/text/visual-model-impl.h>
40
41 using std::vector;
42
43 namespace
44 {
45
46 const float MAX_FLOAT = std::numeric_limits<float>::max();
47 const std::string EMPTY_STRING;
48
49 enum ModifyType
50 {
51   REPLACE_TEXT, ///< Replace the entire text
52   INSERT_TEXT,  ///< Insert characters at the current cursor position
53   DELETE_TEXT   ///< Delete a character at the current cursor position
54 };
55
56 struct ModifyEvent
57 {
58   ModifyType type;
59   std::string text;
60 };
61
62 } // namespace
63
64 namespace Dali
65 {
66
67 namespace Toolkit
68 {
69
70 namespace Text
71 {
72
73 struct Controller::TextInput
74 {
75   // Used to queue input events until DoRelayout()
76   enum EventType
77   {
78     KEYBOARD_FOCUS_GAIN_EVENT,
79     KEYBOARD_FOCUS_LOST_EVENT,
80     CURSOR_KEY_EVENT,
81     TAP_EVENT,
82     PAN_EVENT,
83     GRAB_HANDLE_EVENT
84   };
85
86   union Param
87   {
88     int mInt;
89     unsigned int mUint;
90     float mFloat;
91   };
92
93   struct Event
94   {
95     Event( EventType eventType )
96     : type( eventType )
97     {
98       p1.mInt = 0;
99       p2.mInt = 0;
100     }
101
102     EventType type;
103     Param p1;
104     Param p2;
105     Param p3;
106   };
107
108   enum State
109   {
110     INACTIVE,
111     SELECTING,
112     EDITING,
113     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     // Set the text properties to default
655     mVisualModel->SetTextColor( Color::WHITE );
656     mVisualModel->SetShadowOffset( Vector2::ZERO );
657     mVisualModel->SetShadowColor( Vector4::ZERO );
658     mVisualModel->SetUnderlineEnabled( false );
659   }
660
661   ~Impl()
662   {
663     delete mTextInput;
664   }
665
666   ControlInterface& mControlInterface;     ///< Reference to the text controller.
667   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
668   VisualModelPtr  mVisualModel;            ///< Pointer to the visual model.
669   FontDefaults* mFontDefaults;             ///< Avoid allocating this when the user does not specify a font.
670   Controller::TextInput* mTextInput;       ///< Avoid allocating everything for text input until EnableTextInput().
671   TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
672   View mView;                              ///< The view interface to the rendering back-end.
673   LayoutEngine mLayoutEngine;              ///< The layout engine.
674   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
675   Size mControlSize;                       ///< The size of the control.
676   Vector2 mAlignmentOffset;                ///< Vertical and horizontal offset of the whole text inside the control due to alignment.
677   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
678   bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
679 };
680
681 ControllerPtr Controller::New( ControlInterface& controlInterface )
682 {
683   return ControllerPtr( new Controller( controlInterface ) );
684 }
685
686 void Controller::SetText( const std::string& text )
687 {
688   // Cancel previously queued inserts etc.
689   mImpl->mModifyEvents.clear();
690
691   // Keep until size negotiation
692   ModifyEvent event;
693   event.type = REPLACE_TEXT;
694   event.text = text;
695   mImpl->mModifyEvents.push_back( event );
696
697   if( mImpl->mTextInput )
698   {
699     // Cancel previously queued events
700     mImpl->mTextInput->mEventQueue.clear();
701
702     // TODO - Hide selection decorations
703   }
704 }
705
706 void Controller::GetText( std::string& text ) const
707 {
708   if( !mImpl->mModifyEvents.empty() &&
709        REPLACE_TEXT == mImpl->mModifyEvents[0].type )
710   {
711     text = mImpl->mModifyEvents[0].text;
712   }
713   else
714   {
715     // TODO - Convert from UTF-32
716   }
717 }
718
719 void Controller::SetPlaceholderText( const std::string& text )
720 {
721   if( !mImpl->mTextInput )
722   {
723     mImpl->mTextInput->mPlaceholderText = text;
724   }
725 }
726
727 void Controller::GetPlaceholderText( std::string& text ) const
728 {
729   if( !mImpl->mTextInput )
730   {
731     text = mImpl->mTextInput->mPlaceholderText;
732   }
733 }
734
735 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
736 {
737   if( !mImpl->mFontDefaults )
738   {
739     mImpl->mFontDefaults = new Controller::FontDefaults();
740   }
741
742   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
743   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
744   mImpl->mOperationsPending = ALL_OPERATIONS;
745   mImpl->mRecalculateNaturalSize = true;
746
747   // Clear the font-specific data
748   mImpl->mLogicalModel->mFontRuns.Clear();
749   mImpl->mVisualModel->mGlyphs.Clear();
750   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
751   mImpl->mVisualModel->mCharactersToGlyph.Clear();
752   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
753   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
754   mImpl->mVisualModel->mGlyphPositions.Clear();
755   mImpl->mVisualModel->mLines.Clear();
756
757   RequestRelayout();
758 }
759
760 const std::string& Controller::GetDefaultFontFamily() const
761 {
762   if( mImpl->mFontDefaults )
763   {
764     return mImpl->mFontDefaults->mDefaultFontFamily;
765   }
766
767   return EMPTY_STRING;
768 }
769
770 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
771 {
772   if( !mImpl->mFontDefaults )
773   {
774     mImpl->mFontDefaults = new Controller::FontDefaults();
775   }
776
777   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
778   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
779   mImpl->mOperationsPending = ALL_OPERATIONS;
780   mImpl->mRecalculateNaturalSize = true;
781
782   // Clear the font-specific data
783   mImpl->mLogicalModel->mFontRuns.Clear();
784   mImpl->mVisualModel->mGlyphs.Clear();
785   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
786   mImpl->mVisualModel->mCharactersToGlyph.Clear();
787   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
788   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
789   mImpl->mVisualModel->mGlyphPositions.Clear();
790   mImpl->mVisualModel->mLines.Clear();
791
792   RequestRelayout();
793 }
794
795 const std::string& Controller::GetDefaultFontStyle() const
796 {
797   if( mImpl->mFontDefaults )
798   {
799     return mImpl->mFontDefaults->mDefaultFontStyle;
800   }
801
802   return EMPTY_STRING;
803 }
804
805 void Controller::SetDefaultPointSize( float pointSize )
806 {
807   if( !mImpl->mFontDefaults )
808   {
809     mImpl->mFontDefaults = new Controller::FontDefaults();
810   }
811
812   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
813   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
814   mImpl->mOperationsPending = ALL_OPERATIONS;
815   mImpl->mRecalculateNaturalSize = true;
816
817   // Clear the font-specific data
818   mImpl->mLogicalModel->mFontRuns.Clear();
819   mImpl->mVisualModel->mGlyphs.Clear();
820   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
821   mImpl->mVisualModel->mCharactersToGlyph.Clear();
822   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
823   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
824   mImpl->mVisualModel->mGlyphPositions.Clear();
825   mImpl->mVisualModel->mLines.Clear();
826
827   RequestRelayout();
828 }
829
830 float Controller::GetDefaultPointSize() const
831 {
832   if( mImpl->mFontDefaults )
833   {
834     return mImpl->mFontDefaults->mDefaultPointSize;
835   }
836
837   return 0.0f;
838 }
839
840 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
841 {
842   if( mImpl->mFontDefaults )
843   {
844     FontRun fontRun;
845     fontRun.characterRun.characterIndex = 0;
846     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
847     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
848     fontRun.isDefault = true;
849
850     fonts.PushBack( fontRun );
851   }
852 }
853
854 const Vector4& Controller::GetTextColor() const
855 {
856   return mImpl->mVisualModel->GetTextColor();
857 }
858
859 const Vector2& Controller::GetShadowOffset() const
860 {
861   return mImpl->mVisualModel->GetShadowOffset();
862 }
863
864 const Vector4& Controller::GetShadowColor() const
865 {
866   return mImpl->mVisualModel->GetShadowColor();
867 }
868
869 const Vector4& Controller::GetUnderlineColor() const
870 {
871   return mImpl->mVisualModel->GetUnderlineColor();
872 }
873
874 bool Controller::IsUnderlineEnabled() const
875 {
876   return mImpl->mVisualModel->IsUnderlineEnabled();
877 }
878
879 void Controller::SetTextColor( const Vector4& textColor )
880 {
881   mImpl->mVisualModel->SetTextColor( textColor );
882 }
883
884 void Controller::SetShadowOffset( const Vector2& shadowOffset )
885 {
886   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
887 }
888
889 void Controller::SetShadowColor( const Vector4& shadowColor )
890 {
891   mImpl->mVisualModel->SetShadowColor( shadowColor );
892 }
893
894 void Controller::SetUnderlineColor( const Vector4& color )
895 {
896   mImpl->mVisualModel->SetUnderlineColor( color );
897 }
898
899 void Controller::SetUnderlineEnabled( bool enabled )
900 {
901   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
902 }
903
904 void Controller::EnableTextInput( DecoratorPtr decorator )
905 {
906   if( !mImpl->mTextInput )
907   {
908     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
909   }
910 }
911
912 void Controller::SetEnableCursorBlink( bool enable )
913 {
914   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
915
916   if( mImpl->mTextInput )
917   {
918     mImpl->mTextInput->mCursorBlinkEnabled = enable;
919
920     if( !enable &&
921         mImpl->mTextInput->mDecorator )
922     {
923       mImpl->mTextInput->mDecorator->StopCursorBlink();
924     }
925   }
926 }
927
928 bool Controller::GetEnableCursorBlink() const
929 {
930   if( mImpl->mTextInput )
931   {
932     return mImpl->mTextInput->mCursorBlinkEnabled;
933   }
934
935   return false;
936 }
937
938 const Vector2& Controller::GetScrollPosition() const
939 {
940   if( mImpl->mTextInput )
941   {
942     return mImpl->mTextInput->mScrollPosition;
943   }
944
945   return Vector2::ZERO;
946 }
947
948 const Vector2& Controller::GetAlignmentOffset() const
949 {
950   return mImpl->mAlignmentOffset;
951 }
952
953 Vector3 Controller::GetNaturalSize()
954 {
955   Vector3 naturalSize;
956
957   // Make sure the model is up-to-date before layouting
958   ProcessModifyEvents();
959
960   if( mImpl->mRecalculateNaturalSize )
961   {
962     // Operations that can be done only once until the text changes.
963     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
964                                                                            GET_SCRIPTS       |
965                                                                            VALIDATE_FONTS    |
966                                                                            GET_LINE_BREAKS   |
967                                                                            GET_WORD_BREAKS   |
968                                                                            BIDI_INFO         |
969                                                                            SHAPE_TEXT        |
970                                                                            GET_GLYPH_METRICS );
971     // Make sure the model is up-to-date before layouting
972     UpdateModel( onlyOnceOperations );
973
974     // Operations that need to be done if the size changes.
975     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
976                                                                         ALIGN  |
977                                                                         REORDER );
978
979     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
980                 static_cast<OperationsMask>( onlyOnceOperations |
981                                              sizeOperations ),
982                 naturalSize.GetVectorXY() );
983
984     // Do not do again the only once operations.
985     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
986
987     // Do the size related operations again.
988     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
989
990     // Stores the natural size to avoid recalculate it again
991     // unless the text/style changes.
992     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
993
994     mImpl->mRecalculateNaturalSize = false;
995   }
996   else
997   {
998     naturalSize = mImpl->mVisualModel->GetNaturalSize();
999   }
1000
1001   return naturalSize;
1002 }
1003
1004 float Controller::GetHeightForWidth( float width )
1005 {
1006   // Make sure the model is up-to-date before layouting
1007   ProcessModifyEvents();
1008
1009   Size layoutSize;
1010   if( width != mImpl->mControlSize.width )
1011   {
1012     // Operations that can be done only once until the text changes.
1013     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1014                                                                            GET_SCRIPTS       |
1015                                                                            VALIDATE_FONTS    |
1016                                                                            GET_LINE_BREAKS   |
1017                                                                            GET_WORD_BREAKS   |
1018                                                                            BIDI_INFO         |
1019                                                                            SHAPE_TEXT        |
1020                                                                            GET_GLYPH_METRICS );
1021     // Make sure the model is up-to-date before layouting
1022     UpdateModel( onlyOnceOperations );
1023
1024     // Operations that need to be done if the size changes.
1025     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1026                                                                         ALIGN  |
1027                                                                         REORDER );
1028
1029     DoRelayout( Size( width, MAX_FLOAT ),
1030                 static_cast<OperationsMask>( onlyOnceOperations |
1031                                              sizeOperations ),
1032                 layoutSize );
1033
1034     // Do not do again the only once operations.
1035     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1036
1037     // Do the size related operations again.
1038     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1039   }
1040   else
1041   {
1042     layoutSize = mImpl->mVisualModel->GetActualSize();
1043   }
1044
1045   return layoutSize.height;
1046 }
1047
1048 bool Controller::Relayout( const Size& size )
1049 {
1050   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1051   {
1052     bool glyphsRemoved( false );
1053     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
1054     {
1055       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
1056       glyphsRemoved = true;
1057     }
1058
1059     // Not worth to relayout if width or height is equal to zero.
1060     return glyphsRemoved;
1061   }
1062
1063   if( size != mImpl->mControlSize )
1064   {
1065     // Operations that need to be done if the size changes.
1066     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1067                                                              LAYOUT                    |
1068                                                              ALIGN                     |
1069                                                              UPDATE_ACTUAL_SIZE        |
1070                                                              REORDER );
1071
1072     mImpl->mControlSize = size;
1073   }
1074
1075   // Make sure the model is up-to-date before layouting
1076   ProcessModifyEvents();
1077   UpdateModel( mImpl->mOperationsPending );
1078
1079   Size layoutSize;
1080   bool updated = DoRelayout( mImpl->mControlSize,
1081                              mImpl->mOperationsPending,
1082                              layoutSize );
1083
1084   // Do not re-do any operation until something changes.
1085   mImpl->mOperationsPending = NO_OPERATION;
1086
1087   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
1088   CalculateTextAlignment( size );
1089
1090   if( mImpl->mTextInput )
1091   {
1092     // Move the cursor, grab handle etc.
1093     updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize, mImpl->mAlignmentOffset ) || updated;
1094   }
1095
1096   return updated;
1097 }
1098
1099 void Controller::ProcessModifyEvents()
1100 {
1101   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
1102
1103   for( unsigned int i=0; i<events.size(); ++i )
1104   {
1105     if( REPLACE_TEXT == events[0].type )
1106     {
1107       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
1108       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
1109
1110       ReplaceTextEvent( events[0].text );
1111     }
1112     else if( INSERT_TEXT == events[0].type )
1113     {
1114       InsertTextEvent( events[0].text );
1115     }
1116     else if( DELETE_TEXT == events[0].type )
1117     {
1118       DeleteTextEvent();
1119     }
1120   }
1121
1122   // Discard temporary text
1123   events.clear();
1124 }
1125
1126 void Controller::ReplaceTextEvent( const std::string& text )
1127 {
1128   // Reset buffers.
1129   mImpl->mLogicalModel->mText.Clear();
1130   mImpl->mLogicalModel->mScriptRuns.Clear();
1131   mImpl->mLogicalModel->mFontRuns.Clear();
1132   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1133   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1134   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1135   mImpl->mLogicalModel->mCharacterDirections.Clear();
1136   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1137   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1138   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1139   mImpl->mVisualModel->mGlyphs.Clear();
1140   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1141   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1142   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1143   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1144   mImpl->mVisualModel->mGlyphPositions.Clear();
1145   mImpl->mVisualModel->mLines.Clear();
1146
1147   //  Convert text into UTF-32
1148   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1149   utf32Characters.Resize( text.size() );
1150
1151   // This is a bit horrible but std::string returns a (signed) char*
1152   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1153
1154   // Transform a text array encoded in utf8 into an array encoded in utf32.
1155   // It returns the actual number of characters.
1156   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1157   utf32Characters.Resize( characterCount );
1158
1159   // Reset the cursor position
1160   if( mImpl->mTextInput )
1161   {
1162     mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
1163     // TODO - handle secondary cursor
1164   }
1165
1166   // The natural size needs to be re-calculated.
1167   mImpl->mRecalculateNaturalSize = true;
1168
1169   // Apply modifications to the model
1170   mImpl->mOperationsPending = ALL_OPERATIONS;
1171   UpdateModel( ALL_OPERATIONS );
1172   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1173                                                            ALIGN              |
1174                                                            UPDATE_ACTUAL_SIZE |
1175                                                            REORDER );
1176 }
1177
1178 void Controller::InsertTextEvent( const std::string& text )
1179 {
1180   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1181
1182   // TODO - Optimize this
1183   mImpl->mLogicalModel->mScriptRuns.Clear();
1184   mImpl->mLogicalModel->mFontRuns.Clear();
1185   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1186   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1187   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1188   mImpl->mLogicalModel->mCharacterDirections.Clear();
1189   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1190   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1191   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1192   mImpl->mVisualModel->mGlyphs.Clear();
1193   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1194   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1195   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1196   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1197   mImpl->mVisualModel->mGlyphPositions.Clear();
1198   mImpl->mVisualModel->mLines.Clear();
1199
1200   //  Convert text into UTF-32
1201   Vector<Character> utf32Characters;
1202   utf32Characters.Resize( text.size() );
1203
1204   // This is a bit horrible but std::string returns a (signed) char*
1205   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1206
1207   // Transform a text array encoded in utf8 into an array encoded in utf32.
1208   // It returns the actual number of characters.
1209   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1210   utf32Characters.Resize( characterCount );
1211
1212   // Insert at current cursor position
1213   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1214   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1215
1216   if( cursorIndex < modifyText.Count() )
1217   {
1218     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
1219   }
1220   else
1221   {
1222     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
1223   }
1224
1225   // Advance the cursor position
1226   ++cursorIndex;
1227
1228   // The natural size needs to be re-calculated.
1229   mImpl->mRecalculateNaturalSize = true;
1230
1231   // Apply modifications to the model; TODO - Optimize this
1232   mImpl->mOperationsPending = ALL_OPERATIONS;
1233   UpdateModel( ALL_OPERATIONS );
1234   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1235                                                            ALIGN              |
1236                                                            UPDATE_ACTUAL_SIZE |
1237                                                            REORDER );
1238
1239   // Queue a cursor reposition event; this must wait until after DoRelayout()
1240   mImpl->mTextInput->mUpdateCursorPosition = true;
1241 }
1242
1243 void Controller::DeleteTextEvent()
1244 {
1245   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1246
1247   // TODO - Optimize this
1248   mImpl->mLogicalModel->mScriptRuns.Clear();
1249   mImpl->mLogicalModel->mFontRuns.Clear();
1250   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1251   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1252   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1253   mImpl->mLogicalModel->mCharacterDirections.Clear();
1254   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1255   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1256   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1257   mImpl->mVisualModel->mGlyphs.Clear();
1258   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1259   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1260   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1261   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1262   mImpl->mVisualModel->mGlyphPositions.Clear();
1263   mImpl->mVisualModel->mLines.Clear();
1264
1265   // Delte at current cursor position
1266   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1267   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1268
1269   if( cursorIndex > 0 &&
1270       cursorIndex-1 < modifyText.Count() )
1271   {
1272     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
1273
1274     // Cursor position retreat
1275     --cursorIndex;
1276   }
1277
1278   // The natural size needs to be re-calculated.
1279   mImpl->mRecalculateNaturalSize = true;
1280
1281   // Apply modifications to the model; TODO - Optimize this
1282   mImpl->mOperationsPending = ALL_OPERATIONS;
1283   UpdateModel( ALL_OPERATIONS );
1284   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1285                                                            ALIGN              |
1286                                                            UPDATE_ACTUAL_SIZE |
1287                                                            REORDER );
1288
1289   // Queue a cursor reposition event; this must wait until after DoRelayout()
1290   mImpl->mTextInput->mUpdateCursorPosition = true;
1291 }
1292
1293 void Controller::UpdateModel( OperationsMask operationsRequired )
1294 {
1295   // Calculate the operations to be done.
1296   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1297
1298   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1299
1300   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
1301
1302   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1303   if( GET_LINE_BREAKS & operations )
1304   {
1305     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
1306     // calculate the bidirectional info for each 'paragraph'.
1307     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
1308     // is not shaped together).
1309     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
1310
1311     SetLineBreakInfo( utf32Characters,
1312                       lineBreakInfo );
1313   }
1314
1315   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1316   if( GET_WORD_BREAKS & operations )
1317   {
1318     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
1319     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
1320
1321     SetWordBreakInfo( utf32Characters,
1322                       wordBreakInfo );
1323   }
1324
1325   const bool getScripts = GET_SCRIPTS & operations;
1326   const bool validateFonts = VALIDATE_FONTS & operations;
1327
1328   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
1329   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
1330
1331   if( getScripts || validateFonts )
1332   {
1333     // Validates the fonts assigned by the application or assigns default ones.
1334     // It makes sure all the characters are going to be rendered by the correct font.
1335     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
1336
1337     if( getScripts )
1338     {
1339       // Retrieves the scripts used in the text.
1340       multilanguageSupport.SetScripts( utf32Characters,
1341                                        lineBreakInfo,
1342                                        scripts );
1343     }
1344
1345     if( validateFonts )
1346     {
1347       if( 0u == validFonts.Count() )
1348       {
1349         // Copy the requested font defaults received via the property system.
1350         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
1351         GetDefaultFonts( validFonts, numberOfCharacters );
1352       }
1353
1354       // Validates the fonts. If there is a character with no assigned font it sets a default one.
1355       // After this call, fonts are validated.
1356       multilanguageSupport.ValidateFonts( utf32Characters,
1357                                           scripts,
1358                                           validFonts );
1359     }
1360   }
1361
1362   Vector<Character> mirroredUtf32Characters;
1363   bool textMirrored = false;
1364   if( BIDI_INFO & operations )
1365   {
1366     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
1367     // bidirectional info.
1368
1369     Length numberOfParagraphs = 0u;
1370
1371     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
1372     for( Length index = 0u; index < numberOfCharacters; ++index )
1373     {
1374       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
1375       {
1376         ++numberOfParagraphs;
1377       }
1378     }
1379
1380     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1381     bidirectionalInfo.Reserve( numberOfParagraphs );
1382
1383     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1384     SetBidirectionalInfo( utf32Characters,
1385                           scripts,
1386                           lineBreakInfo,
1387                           bidirectionalInfo );
1388
1389     if( 0u != bidirectionalInfo.Count() )
1390     {
1391       // This paragraph has right to left text. Some characters may need to be mirrored.
1392       // TODO: consider if the mirrored string can be stored as well.
1393
1394       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
1395
1396       // Only set the character directions if there is right to left characters.
1397       Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
1398       directions.Resize( numberOfCharacters );
1399
1400       GetCharactersDirection( bidirectionalInfo,
1401                               directions );
1402     }
1403     else
1404     {
1405       // There is no right to left characters. Clear the directions vector.
1406       mImpl->mLogicalModel->mCharacterDirections.Clear();
1407     }
1408
1409    }
1410
1411   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1412   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1413   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1414   if( SHAPE_TEXT & operations )
1415   {
1416     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1417     // Shapes the text.
1418     ShapeText( textToShape,
1419                lineBreakInfo,
1420                scripts,
1421                validFonts,
1422                glyphs,
1423                glyphsToCharactersMap,
1424                charactersPerGlyph );
1425
1426     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
1427     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
1428     mImpl->mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
1429   }
1430
1431   const Length numberOfGlyphs = glyphs.Count();
1432
1433   if( GET_GLYPH_METRICS & operations )
1434   {
1435     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
1436   }
1437 }
1438
1439 bool Controller::DoRelayout( const Size& size,
1440                              OperationsMask operationsRequired,
1441                              Size& layoutSize )
1442 {
1443   bool viewUpdated( false );
1444
1445   // Calculate the operations to be done.
1446   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1447
1448   if( LAYOUT & operations )
1449   {
1450     // Some vectors with data needed to layout and reorder may be void
1451     // after the first time the text has been laid out.
1452     // Fill the vectors again.
1453
1454     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
1455
1456     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1457     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1458     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1459     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1460     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1461
1462     // Set the layout parameters.
1463     LayoutParameters layoutParameters( size,
1464                                        mImpl->mLogicalModel->mText.Begin(),
1465                                        lineBreakInfo.Begin(),
1466                                        wordBreakInfo.Begin(),
1467                                        numberOfGlyphs,
1468                                        glyphs.Begin(),
1469                                        glyphsToCharactersMap.Begin(),
1470                                        charactersPerGlyph.Begin() );
1471
1472     // The laid-out lines.
1473     // It's not possible to know in how many lines the text is going to be laid-out,
1474     // but it can be resized at least with the number of 'paragraphs' to avoid
1475     // some re-allocations.
1476     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1477
1478     // Delete any previous laid out lines before setting the new ones.
1479     lines.Clear();
1480
1481     // The capacity of the bidirectional paragraph info is the number of paragraphs.
1482     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
1483
1484     // Resize the vector of positions to have the same size than the vector of glyphs.
1485     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1486     glyphPositions.Resize( numberOfGlyphs );
1487
1488     // Update the visual model.
1489     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1490                                                    glyphPositions,
1491                                                    lines,
1492                                                    layoutSize );
1493
1494     if( viewUpdated )
1495     {
1496       // Reorder the lines
1497       if( REORDER & operations )
1498       {
1499         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1500
1501         // Check first if there are paragraphs with bidirectional info.
1502         if( 0u != bidirectionalInfo.Count() )
1503         {
1504           // Get the lines
1505           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
1506
1507           // Reorder the lines.
1508           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1509           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1510           ReorderLines( bidirectionalInfo,
1511                         lines,
1512                         lineBidirectionalInfoRuns );
1513
1514           // Set the bidirectional info into the model.
1515           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1516           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1517                                                        numberOfBidirectionalInfoRuns );
1518
1519           // Set the bidirectional info per line into the layout parameters.
1520           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1521           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1522
1523           // Get the character to glyph conversion table and set into the layout.
1524           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1525
1526           // Get the glyphs per character table and set into the layout.
1527           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1528
1529           // Re-layout the text. Reorder those lines with right to left characters.
1530           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1531                                                          glyphPositions );
1532
1533           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1534           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1535                  endIt = lineBidirectionalInfoRuns.End();
1536                it != endIt;
1537                ++it )
1538           {
1539             BidirectionalLineInfoRun& bidiLineInfo = *it;
1540
1541             free( bidiLineInfo.visualToLogicalMap );
1542           }
1543         }
1544       } // REORDER
1545
1546       if( ALIGN & operations )
1547       {
1548         mImpl->mLayoutEngine.Align( layoutParameters,
1549                                     layoutSize,
1550                                     lines,
1551                                     glyphPositions );
1552       }
1553
1554       // Sets the actual size.
1555       if( UPDATE_ACTUAL_SIZE & operations )
1556       {
1557         mImpl->mVisualModel->SetActualSize( layoutSize );
1558       }
1559     } // view updated
1560   }
1561   else
1562   {
1563     layoutSize = mImpl->mVisualModel->GetActualSize();
1564   }
1565
1566   return viewUpdated;
1567 }
1568
1569 void Controller::CalculateTextAlignment( const Size& size )
1570 {
1571   // Get the direction of the first character.
1572   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
1573
1574   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
1575
1576   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
1577   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
1578   if( firstParagraphDirection &&
1579       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
1580   {
1581     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
1582     {
1583       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
1584     }
1585     else
1586     {
1587       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
1588     }
1589   }
1590
1591   switch( horizontalAlignment )
1592   {
1593     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1594     {
1595       mImpl->mAlignmentOffset.x = 0.f;
1596       break;
1597     }
1598     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1599     {
1600       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1601       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
1602       break;
1603     }
1604     case LayoutEngine::HORIZONTAL_ALIGN_END:
1605     {
1606       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1607       break;
1608     }
1609   }
1610
1611   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1612   switch( verticalAlignment )
1613   {
1614     case LayoutEngine::VERTICAL_ALIGN_TOP:
1615     {
1616       mImpl->mAlignmentOffset.y = 0.f;
1617       break;
1618     }
1619     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1620     {
1621       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1622       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
1623       break;
1624     }
1625     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1626     {
1627       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1628       break;
1629     }
1630   }
1631 }
1632
1633 View& Controller::GetView()
1634 {
1635   return mImpl->mView;
1636 }
1637
1638 LayoutEngine& Controller::GetLayoutEngine()
1639 {
1640   return mImpl->mLayoutEngine;
1641 }
1642
1643 void Controller::RequestRelayout()
1644 {
1645   mImpl->mControlInterface.RequestTextRelayout();
1646 }
1647
1648 void Controller::KeyboardFocusGainEvent()
1649 {
1650   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1651
1652   if( mImpl->mTextInput )
1653   {
1654     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1655     mImpl->mTextInput->mEventQueue.push_back( event );
1656
1657     RequestRelayout();
1658   }
1659 }
1660
1661 void Controller::KeyboardFocusLostEvent()
1662 {
1663   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1664
1665   if( mImpl->mTextInput )
1666   {
1667     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1668     mImpl->mTextInput->mEventQueue.push_back( event );
1669
1670     RequestRelayout();
1671   }
1672 }
1673
1674 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1675 {
1676   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1677
1678   if( mImpl->mTextInput &&
1679       keyEvent.state == KeyEvent::Down )
1680   {
1681     int keyCode = keyEvent.keyCode;
1682     const std::string& keyString = keyEvent.keyPressed;
1683
1684     // Pre-process to separate modifying events from non-modifying input events.
1685     if( Dali::DALI_KEY_ESCAPE == keyCode )
1686     {
1687       // Escape key is a special case which causes focus loss
1688       KeyboardFocusLostEvent();
1689     }
1690     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1691              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1692              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1693              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1694     {
1695       TextInput::Event event( TextInput::CURSOR_KEY_EVENT );
1696       event.p1.mInt = keyCode;
1697       mImpl->mTextInput->mEventQueue.push_back( event );
1698     }
1699     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1700     {
1701       // Queue a delete event
1702       ModifyEvent event;
1703       event.type = DELETE_TEXT;
1704       mImpl->mModifyEvents.push_back( event );
1705     }
1706     else if( !keyString.empty() )
1707     {
1708       // Queue an insert event
1709       ModifyEvent event;
1710       event.type = INSERT_TEXT;
1711       event.text = keyString;
1712       mImpl->mModifyEvents.push_back( event );
1713     }
1714
1715     mImpl->mTextInput->ChangeState( TextInput::EDITING ); // todo Confirm this is the best place to change the state of
1716
1717     RequestRelayout();
1718   }
1719
1720   return false;
1721 }
1722
1723 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1724 {
1725   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1726
1727   if( mImpl->mTextInput )
1728   {
1729     TextInput::Event event( TextInput::TAP_EVENT );
1730     event.p1.mUint = tapCount;
1731     event.p2.mFloat = x;
1732     event.p3.mFloat = y;
1733     mImpl->mTextInput->mEventQueue.push_back( event );
1734
1735     RequestRelayout();
1736   }
1737 }
1738
1739 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1740 {
1741   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected PanEvent" );
1742
1743   if( mImpl->mTextInput )
1744   {
1745     TextInput::Event event( TextInput::PAN_EVENT );
1746     event.p1.mInt = state;
1747     event.p2.mFloat = displacement.x;
1748     event.p3.mFloat = displacement.y;
1749     mImpl->mTextInput->mEventQueue.push_back( event );
1750
1751     RequestRelayout();
1752   }
1753 }
1754
1755 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1756 {
1757   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1758
1759   if( mImpl->mTextInput )
1760   {
1761     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1762     event.p1.mUint  = state;
1763     event.p2.mFloat = x;
1764     event.p3.mFloat = y;
1765     mImpl->mTextInput->mEventQueue.push_back( event );
1766
1767     RequestRelayout();
1768   }
1769 }
1770
1771 Controller::~Controller()
1772 {
1773   delete mImpl;
1774 }
1775
1776 Controller::Controller( ControlInterface& controlInterface )
1777 : mImpl( NULL )
1778 {
1779   mImpl = new Controller::Impl( controlInterface );
1780 }
1781
1782 } // namespace Text
1783
1784 } // namespace Toolkit
1785
1786 } // namespace Dali