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