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