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