74ab9ae38bc9a5d728adfc6b8720ee9f41446ac0
[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     GRAB_HANDLE_EVENT
83   };
84
85   union Param
86   {
87     int mInt;
88     unsigned int mUint;
89     float mFloat;
90   };
91
92   struct Event
93   {
94     Event( EventType eventType )
95     : type( eventType )
96     {
97       p1.mInt = 0;
98       p2.mInt = 0;
99     }
100
101     EventType type;
102     Param p1;
103     Param p2;
104     Param p3;
105   };
106
107   enum State
108   {
109     INACTIVE,
110     SELECTING,
111     EDITING
112   };
113
114   TextInput( LogicalModelPtr logicalModel,
115              VisualModelPtr visualModel,
116              DecoratorPtr decorator )
117   : mLogicalModel( logicalModel ),
118     mVisualModel( visualModel ),
119     mDecorator( decorator ),
120     mState( INACTIVE ),
121     mPrimaryCursorPosition( 0u ),
122     mSecondaryCursorPosition( 0u ),
123     mDecoratorUpdated( false ),
124     mCursorBlinkEnabled( true )
125   {
126   }
127
128   /**
129    * @brief Helper to move the cursor, grab handle etc.
130    */
131   bool ProcessInputEvents()
132   {
133     mDecoratorUpdated = false;
134
135     if( mDecorator )
136     {
137       for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
138       {
139         switch( iter->type )
140         {
141           case KEYBOARD_FOCUS_GAIN_EVENT:
142           {
143             OnKeyboardFocus( true );
144             break;
145           }
146           case KEYBOARD_FOCUS_LOST_EVENT:
147           {
148             OnKeyboardFocus( false );
149             break;
150           }
151           case CURSOR_KEY_EVENT:
152           {
153             OnCursorKeyEvent( *iter );
154             break;
155           }
156           case TAP_EVENT:
157           {
158             OnTapEvent( *iter );
159             break;
160           }
161           case GRAB_HANDLE_EVENT:
162           {
163             OnGrabHandleEvent( *iter );
164             break;
165           }
166         }
167       }
168     }
169
170     mEventQueue.clear();
171
172     return mDecoratorUpdated;
173   }
174
175   void OnKeyboardFocus( bool hasFocus )
176   {
177     if( !hasFocus )
178     {
179       ChangeState( INACTIVE );
180     }
181     else
182     {
183       ChangeState( EDITING );
184     }
185   }
186
187   void OnCursorKeyEvent( const Event& event )
188   {
189     int keyCode = event.p1.mInt;
190
191     if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
192     {
193       // TODO
194     }
195     else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
196     {
197       // TODO
198     }
199     else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
200     {
201       // TODO
202     }
203     else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
204     {
205       // TODO
206     }
207   }
208
209   void HandleBackspaceKey()
210   {
211     // TODO
212   }
213
214   void HandleCursorKey( int keyCode )
215   {
216     // TODO
217   }
218
219   void HandleKeyString( const char* keyString )
220   {
221     // TODO
222   }
223
224   void OnTapEvent( const Event& event )
225   {
226     unsigned int tapCount = event.p1.mUint;
227
228     if( 1u == tapCount )
229     {
230       ChangeState( EDITING );
231
232       float xPosition = event.p2.mFloat;
233       float yPosition = event.p3.mFloat;
234       float height(0.0f);
235       GetClosestCursorPosition( xPosition, yPosition, height );
236       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
237
238       mDecoratorUpdated = true;
239     }
240     else if( 2u == tapCount )
241     {
242       ChangeState( SELECTING );
243     }
244   }
245
246   void OnGrabHandleEvent( const Event& event )
247   {
248     unsigned int state = event.p1.mUint;
249
250     if( GRAB_HANDLE_PRESSED == state )
251     {
252       float xPosition = event.p2.mFloat;
253       float yPosition = event.p3.mFloat;
254       float height(0.0f);
255
256       GetClosestCursorPosition( xPosition, yPosition, height );
257
258       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
259       mDecorator->HidePopup();
260       mDecoratorUpdated = true;
261     }
262     else if ( GRAB_HANDLE_RELEASED == state )
263     {
264       mDecorator->ShowPopup();
265     }
266
267   }
268
269   void ChangeState( State newState )
270   {
271     if( mState != newState )
272     {
273       mState = newState;
274
275       if( INACTIVE == mState )
276       {
277         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
278         mDecorator->StopCursorBlink();
279         mDecorator->SetGrabHandleActive( false );
280         mDecorator->SetSelectionActive( false );
281         mDecorator->HidePopup();
282         mDecoratorUpdated = true;
283       }
284       else if ( SELECTING == mState )
285       {
286         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
287         mDecorator->StopCursorBlink();
288         mDecorator->SetGrabHandleActive( false );
289         mDecorator->SetSelectionActive( true );
290         mDecoratorUpdated = true;
291       }
292       else if( EDITING == mState )
293       {
294         mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
295         if( mCursorBlinkEnabled )
296         {
297           mDecorator->StartCursorBlink();
298         }
299         mDecorator->SetGrabHandleActive( true );
300         mDecorator->SetSelectionActive( false );
301         mDecoratorUpdated = true;
302       }
303     }
304   }
305
306   void GetClosestCursorPosition( float& x, float& y, float& height )
307   {
308     // TODO - Look at LineRuns first
309
310     Text::Length numberOfGlyphs = mVisualModel->GetNumberOfGlyphs();
311     if( 0 == numberOfGlyphs )
312     {
313       return;
314     }
315
316     Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
317     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
318
319     Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
320     const Vector2* const positionsBuffer = positions.Begin();
321
322     unsigned int closestGlyph = 0;
323     float closestDistance = MAX_FLOAT;
324
325     for( unsigned int i = 0, numberOfGLyphs = glyphs.Count(); i < numberOfGLyphs; ++i )
326     {
327       const GlyphInfo& glyphInfo = *( glyphsBuffer + i );
328       const Vector2& position = *( positionsBuffer + i );
329       float glyphX = position.x + glyphInfo.width*0.5f;
330       float glyphY = position.y + glyphInfo.height*0.5f;
331
332       float distanceToGlyph = fabsf( glyphX - x ) + fabsf( glyphY - y );
333
334       if( distanceToGlyph < closestDistance )
335       {
336         closestDistance = distanceToGlyph;
337         closestGlyph = i;
338       }
339     }
340
341     // TODO - Consider RTL languages
342     x = positions[closestGlyph].x + glyphs[closestGlyph].width;
343     y = 0.0f;
344
345     FontMetrics metrics;
346     TextAbstraction::FontClient::Get().GetFontMetrics( glyphs[closestGlyph].fontId, metrics );
347     height = metrics.height; // TODO - Fix for multi-line
348   }
349
350   LogicalModelPtr mLogicalModel;
351   VisualModelPtr  mVisualModel;
352   DecoratorPtr    mDecorator;
353
354   std::string mPlaceholderText;
355
356   /**
357    * This is used to delay handling events until after the model has been updated.
358    * The number of updates to the model is minimized to improve performance.
359    */
360   vector<Event> mEventQueue; ///< The queue of touch events etc.
361
362   State mState; ///< Selection mode, edit mode etc.
363
364   CharacterIndex mPrimaryCursorPosition;   ///< Index into logical model for primary cursor
365   CharacterIndex mSecondaryCursorPosition; ///< Index into logical model for secondary cursor
366
367   bool mDecoratorUpdated   : 1; ///< True if the decorator was updated during event processing
368   bool mCursorBlinkEnabled : 1; ///< True if cursor should blink when active
369 };
370
371 struct Controller::FontDefaults
372 {
373   FontDefaults()
374   : mDefaultPointSize(0.0f),
375     mFontId(0u)
376   {
377   }
378
379   FontId GetFontId( TextAbstraction::FontClient& fontClient )
380   {
381     if( !mFontId )
382     {
383       Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
384       mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
385     }
386
387     return mFontId;
388   }
389
390   std::string mDefaultFontFamily;
391   std::string mDefaultFontStyle;
392   float mDefaultPointSize;
393   FontId mFontId;
394 };
395
396 struct Controller::Impl
397 {
398   Impl( ControlInterface& controlInterface )
399   : mControlInterface( controlInterface ),
400     mLogicalModel(),
401     mVisualModel(),
402     mFontDefaults( NULL ),
403     mTextInput( NULL ),
404     mFontClient(),
405     mView(),
406     mLayoutEngine(),
407     mModifyEvents(),
408     mControlSize(),
409     mOperationsPending( NO_OPERATION ),
410     mRecalculateNaturalSize( true )
411   {
412     mLogicalModel = LogicalModel::New();
413     mVisualModel  = VisualModel::New();
414
415     mFontClient = TextAbstraction::FontClient::Get();
416
417     mView.SetVisualModel( mVisualModel );
418   }
419
420   ~Impl()
421   {
422     delete mTextInput;
423   }
424
425   ControlInterface& mControlInterface;     ///< Reference to the text controller.
426   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
427   VisualModelPtr  mVisualModel;            ///< Pointer to the visual model.
428   FontDefaults* mFontDefaults;             ///< Avoid allocating this when the user does not specify a font.
429   Controller::TextInput* mTextInput;       ///< Avoid allocating everything for text input until EnableTextInput().
430   TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
431   View mView;                              ///< The view interface to the rendering back-end.
432   LayoutEngine mLayoutEngine;              ///< The layout engine.
433   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
434   Size mControlSize;                       ///< The size of the control.
435   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
436   bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
437 };
438
439 ControllerPtr Controller::New( ControlInterface& controlInterface )
440 {
441   return ControllerPtr( new Controller( controlInterface ) );
442 }
443
444 void Controller::SetText( const std::string& text )
445 {
446   // Cancel previously queued inserts etc.
447   mImpl->mModifyEvents.clear();
448
449   // Keep until size negotiation
450   ModifyEvent event;
451   event.type = REPLACE_TEXT;
452   event.text = text;
453   mImpl->mModifyEvents.push_back( event );
454
455   if( mImpl->mTextInput )
456   {
457     // Cancel previously queued events
458     mImpl->mTextInput->mEventQueue.clear();
459
460     // TODO - Hide selection decorations
461   }
462 }
463
464 void Controller::GetText( std::string& text ) const
465 {
466   if( !mImpl->mModifyEvents.empty() &&
467        REPLACE_TEXT == mImpl->mModifyEvents[0].type )
468   {
469     text = mImpl->mModifyEvents[0].text;
470   }
471   else
472   {
473     // TODO - Convert from UTF-32
474   }
475 }
476
477 void Controller::SetPlaceholderText( const std::string& text )
478 {
479   if( !mImpl->mTextInput )
480   {
481     mImpl->mTextInput->mPlaceholderText = text;
482   }
483 }
484
485 void Controller::GetPlaceholderText( std::string& text ) const
486 {
487   if( !mImpl->mTextInput )
488   {
489     text = mImpl->mTextInput->mPlaceholderText;
490   }
491 }
492
493 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
494 {
495   if( !mImpl->mFontDefaults )
496   {
497     mImpl->mFontDefaults = new Controller::FontDefaults();
498   }
499
500   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
501   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
502   mImpl->mOperationsPending = ALL_OPERATIONS;
503   mImpl->mRecalculateNaturalSize = true;
504 }
505
506 const std::string& Controller::GetDefaultFontFamily() const
507 {
508   if( mImpl->mFontDefaults )
509   {
510     return mImpl->mFontDefaults->mDefaultFontFamily;
511   }
512
513   return EMPTY_STRING;
514 }
515
516 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
517 {
518   if( !mImpl->mFontDefaults )
519   {
520     mImpl->mFontDefaults = new Controller::FontDefaults();
521   }
522
523   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
524   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
525   mImpl->mOperationsPending = ALL_OPERATIONS;
526   mImpl->mRecalculateNaturalSize = true;
527 }
528
529 const std::string& Controller::GetDefaultFontStyle() const
530 {
531   if( mImpl->mFontDefaults )
532   {
533     return mImpl->mFontDefaults->mDefaultFontStyle;
534   }
535
536   return EMPTY_STRING;
537 }
538
539 void Controller::SetDefaultPointSize( float pointSize )
540 {
541   if( !mImpl->mFontDefaults )
542   {
543     mImpl->mFontDefaults = new Controller::FontDefaults();
544   }
545
546   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
547   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
548   mImpl->mOperationsPending = ALL_OPERATIONS;
549   mImpl->mRecalculateNaturalSize = true;
550 }
551
552 float Controller::GetDefaultPointSize() const
553 {
554   if( mImpl->mFontDefaults )
555   {
556     return mImpl->mFontDefaults->mDefaultPointSize;
557   }
558
559   return 0.0f;
560 }
561
562 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
563 {
564   if( mImpl->mFontDefaults )
565   {
566     FontRun fontRun;
567     fontRun.characterRun.characterIndex = 0;
568     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
569     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
570     fontRun.isDefault = true;
571
572     fonts.PushBack( fontRun );
573   }
574 }
575
576 void Controller::EnableTextInput( DecoratorPtr decorator )
577 {
578   if( !mImpl->mTextInput )
579   {
580     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
581   }
582 }
583
584 void Controller::SetEnableCursorBlink( bool enable )
585 {
586   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
587
588   if( mImpl->mTextInput )
589   {
590     mImpl->mTextInput->mCursorBlinkEnabled = enable;
591
592     if( !enable &&
593         mImpl->mTextInput->mDecorator )
594     {
595       mImpl->mTextInput->mDecorator->StopCursorBlink();
596     }
597   }
598 }
599
600 bool Controller::GetEnableCursorBlink() const
601 {
602   if( mImpl->mTextInput )
603   {
604     return mImpl->mTextInput->mCursorBlinkEnabled;
605   }
606
607   return false;
608 }
609
610 Vector3 Controller::GetNaturalSize()
611 {
612   Vector3 naturalSize;
613
614   // Make sure the model is up-to-date before layouting
615   ProcessModifyEvents();
616
617   if( mImpl->mRecalculateNaturalSize )
618   {
619     // Operations that can be done only once until the text changes.
620     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
621                                                                            GET_SCRIPTS       |
622                                                                            VALIDATE_FONTS    |
623                                                                            GET_LINE_BREAKS   |
624                                                                            GET_WORD_BREAKS   |
625                                                                            BIDI_INFO         |
626                                                                            SHAPE_TEXT        |
627                                                                            GET_GLYPH_METRICS );
628     // Make sure the model is up-to-date before layouting
629     UpdateModel( onlyOnceOperations );
630
631     // Operations that need to be done if the size changes.
632     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
633                                                                         ALIGN  |
634                                                                         REORDER );
635
636     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
637                 static_cast<OperationsMask>( onlyOnceOperations |
638                                              sizeOperations ),
639                 naturalSize.GetVectorXY() );
640
641     // Do not do again the only once operations.
642     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
643
644     // Do the size related operations again.
645     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
646
647     // Stores the natural size to avoid recalculate it again
648     // unless the text/style changes.
649     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
650
651     mImpl->mRecalculateNaturalSize = false;
652   }
653   else
654   {
655     naturalSize = mImpl->mVisualModel->GetNaturalSize();
656   }
657
658   return naturalSize;
659 }
660
661 float Controller::GetHeightForWidth( float width )
662 {
663   // Make sure the model is up-to-date before layouting
664   ProcessModifyEvents();
665
666   Size layoutSize;
667   if( width != mImpl->mControlSize.width )
668   {
669     // Operations that can be done only once until the text changes.
670     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
671                                                                            GET_SCRIPTS       |
672                                                                            VALIDATE_FONTS    |
673                                                                            GET_LINE_BREAKS   |
674                                                                            GET_WORD_BREAKS   |
675                                                                            BIDI_INFO         |
676                                                                            SHAPE_TEXT        |
677                                                                            GET_GLYPH_METRICS );
678     // Make sure the model is up-to-date before layouting
679     UpdateModel( onlyOnceOperations );
680
681     // Operations that need to be done if the size changes.
682     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
683                                                                         ALIGN  |
684                                                                         REORDER );
685
686     DoRelayout( Size( width, MAX_FLOAT ),
687                 static_cast<OperationsMask>( onlyOnceOperations |
688                                              sizeOperations ),
689                 layoutSize );
690
691     // Do not do again the only once operations.
692     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
693
694     // Do the size related operations again.
695     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
696   }
697   else
698   {
699     layoutSize = mImpl->mVisualModel->GetActualSize();
700   }
701
702   return layoutSize.height;
703 }
704
705 bool Controller::Relayout( const Vector2& size )
706 {
707   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
708   {
709     bool glyphsRemoved( false );
710     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
711     {
712       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
713       glyphsRemoved = true;
714     }
715
716     // Not worth to relayout if width or height is equal to zero.
717     return glyphsRemoved;
718   }
719
720   if( size != mImpl->mControlSize )
721   {
722     // Operations that need to be done if the size changes.
723     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
724                                                              LAYOUT                    |
725                                                              ALIGN                     |
726                                                              UPDATE_ACTUAL_SIZE        |
727                                                              REORDER );
728
729     mImpl->mControlSize = size;
730   }
731
732   // Make sure the model is up-to-date before layouting
733   ProcessModifyEvents();
734   UpdateModel( mImpl->mOperationsPending );
735
736   Size layoutSize;
737   bool updated = DoRelayout( mImpl->mControlSize,
738                              mImpl->mOperationsPending,
739                              layoutSize );
740
741   // Do not re-do any operation until something changes.
742   mImpl->mOperationsPending = NO_OPERATION;
743
744   if( mImpl->mTextInput )
745   {
746     // Move the cursor, grab handle etc.
747     updated = mImpl->mTextInput->ProcessInputEvents() || updated;
748   }
749
750   return updated;
751 }
752
753 void Controller::ProcessModifyEvents()
754 {
755   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
756
757   for( unsigned int i=0; i<events.size(); ++i )
758   {
759     if( REPLACE_TEXT == events[0].type )
760     {
761       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
762       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
763
764       ReplaceTextEvent( events[0].text );
765     }
766     else if( INSERT_TEXT == events[0].type )
767     {
768       InsertTextEvent( events[0].text );
769     }
770     else if( DELETE_TEXT == events[0].type )
771     {
772       DeleteTextEvent();
773     }
774   }
775
776   // Discard temporary text
777   events.clear();
778 }
779
780 void Controller::ReplaceTextEvent( const std::string& text )
781 {
782   // Reset buffers.
783   mImpl->mLogicalModel->mText.Clear();
784   mImpl->mLogicalModel->mScriptRuns.Clear();
785   mImpl->mLogicalModel->mFontRuns.Clear();
786   mImpl->mLogicalModel->mLineBreakInfo.Clear();
787   mImpl->mLogicalModel->mWordBreakInfo.Clear();
788   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
789   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
790   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
791   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
792   mImpl->mVisualModel->mGlyphs.Clear();
793   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
794   mImpl->mVisualModel->mCharactersToGlyph.Clear();
795   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
796   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
797   mImpl->mVisualModel->mGlyphPositions.Clear();
798   mImpl->mVisualModel->mLines.Clear();
799
800   //  Convert text into UTF-32
801   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
802   utf32Characters.Resize( text.size() );
803
804   // This is a bit horrible but std::string returns a (signed) char*
805   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
806
807   // Transform a text array encoded in utf8 into an array encoded in utf32.
808   // It returns the actual number of characters.
809   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
810   utf32Characters.Resize( characterCount );
811
812   // Reset the cursor position
813   if( mImpl->mTextInput )
814   {
815     mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
816     // TODO - handle secondary cursor
817   }
818
819   // The natural size needs to be re-calculated.
820   mImpl->mRecalculateNaturalSize = true;
821
822   // Apply modifications to the model
823   mImpl->mOperationsPending = ALL_OPERATIONS;
824   UpdateModel( ALL_OPERATIONS );
825   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
826                                                            ALIGN              |
827                                                            UPDATE_ACTUAL_SIZE |
828                                                            REORDER );
829 }
830
831 void Controller::InsertTextEvent( const std::string& text )
832 {
833   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
834
835   // TODO - Optimize this
836   mImpl->mLogicalModel->mScriptRuns.Clear();
837   mImpl->mLogicalModel->mFontRuns.Clear();
838   mImpl->mLogicalModel->mLineBreakInfo.Clear();
839   mImpl->mLogicalModel->mWordBreakInfo.Clear();
840   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
841   mImpl->mVisualModel->mGlyphs.Clear();
842
843   //  Convert text into UTF-32
844   Vector<Character> utf32Characters;
845   utf32Characters.Resize( text.size() );
846
847   // This is a bit horrible but std::string returns a (signed) char*
848   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
849
850   // Transform a text array encoded in utf8 into an array encoded in utf32.
851   // It returns the actual number of characters.
852   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
853   utf32Characters.Resize( characterCount );
854
855   // Insert at current cursor position
856   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
857   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
858
859   if( cursorIndex < modifyText.Count() )
860   {
861     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
862   }
863   else
864   {
865     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
866   }
867
868   // Advance the cursor position
869   ++cursorIndex;
870
871   // The natural size needs to be re-calculated.
872   mImpl->mRecalculateNaturalSize = true;
873
874   // Apply modifications to the model; TODO - Optimize this
875   mImpl->mOperationsPending = ALL_OPERATIONS;
876   UpdateModel( ALL_OPERATIONS );
877   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
878                                                            ALIGN              |
879                                                            UPDATE_ACTUAL_SIZE |
880                                                            REORDER );
881 }
882
883 void Controller::DeleteTextEvent()
884 {
885   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
886
887   // TODO - Optimize this
888   mImpl->mLogicalModel->mScriptRuns.Clear();
889   mImpl->mLogicalModel->mFontRuns.Clear();
890   mImpl->mLogicalModel->mLineBreakInfo.Clear();
891   mImpl->mLogicalModel->mWordBreakInfo.Clear();
892   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
893   mImpl->mVisualModel->mGlyphs.Clear();
894
895   // Delte at current cursor position
896   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
897   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
898
899   if( cursorIndex > 0 &&
900       cursorIndex-1 < modifyText.Count() )
901   {
902     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
903
904     // Cursor position retreat
905     --cursorIndex;
906   }
907
908   // The natural size needs to be re-calculated.
909   mImpl->mRecalculateNaturalSize = true;
910
911   // Apply modifications to the model; TODO - Optimize this
912   mImpl->mOperationsPending = ALL_OPERATIONS;
913   UpdateModel( ALL_OPERATIONS );
914   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
915                                                            ALIGN              |
916                                                            UPDATE_ACTUAL_SIZE |
917                                                            REORDER );
918 }
919
920 void Controller::UpdateModel( OperationsMask operationsRequired )
921 {
922   // Calculate the operations to be done.
923   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
924
925   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
926
927   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
928
929   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
930   if( GET_LINE_BREAKS & operations )
931   {
932     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
933     // calculate the bidirectional info for each 'paragraph'.
934     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
935     // is not shaped together).
936     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
937
938     SetLineBreakInfo( utf32Characters,
939                       lineBreakInfo );
940   }
941
942   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
943   if( GET_WORD_BREAKS & operations )
944   {
945     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
946     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
947
948     SetWordBreakInfo( utf32Characters,
949                       wordBreakInfo );
950   }
951
952   const bool getScripts = GET_SCRIPTS & operations;
953   const bool validateFonts = VALIDATE_FONTS & operations;
954
955   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
956   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
957
958   if( getScripts || validateFonts )
959   {
960     // Validates the fonts assigned by the application or assigns default ones.
961     // It makes sure all the characters are going to be rendered by the correct font.
962     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
963
964     if( getScripts )
965     {
966       // Retrieves the scripts used in the text.
967       multilanguageSupport.SetScripts( utf32Characters,
968                                        lineBreakInfo,
969                                        scripts );
970     }
971
972     if( validateFonts )
973     {
974       if( 0u == validFonts.Count() )
975       {
976         // Copy the requested font defaults received via the property system.
977         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
978         GetDefaultFonts( validFonts, numberOfCharacters );
979       }
980
981       // Validates the fonts. If there is a character with no assigned font it sets a default one.
982       // After this call, fonts are validated.
983       multilanguageSupport.ValidateFonts( utf32Characters,
984                                           scripts,
985                                           validFonts );
986     }
987   }
988
989   Vector<Character> mirroredUtf32Characters;
990   bool textMirrored = false;
991   if( BIDI_INFO & operations )
992   {
993     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
994     // bidirectional info.
995
996     Length numberOfParagraphs = 0u;
997
998     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
999     for( Length index = 0u; index < numberOfCharacters; ++index )
1000     {
1001       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
1002       {
1003         ++numberOfParagraphs;
1004       }
1005     }
1006
1007     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1008     bidirectionalInfo.Reserve( numberOfParagraphs );
1009
1010     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1011     SetBidirectionalInfo( utf32Characters,
1012                           scripts,
1013                           lineBreakInfo,
1014                           bidirectionalInfo );
1015
1016     if( 0u != bidirectionalInfo.Count() )
1017     {
1018       // This paragraph has right to left text. Some characters may need to be mirrored.
1019       // TODO: consider if the mirrored string can be stored as well.
1020
1021       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
1022     }
1023   }
1024
1025   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1026   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1027   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1028   if( SHAPE_TEXT & operations )
1029   {
1030     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1031     // Shapes the text.
1032     ShapeText( textToShape,
1033                lineBreakInfo,
1034                scripts,
1035                validFonts,
1036                glyphs,
1037                glyphsToCharactersMap,
1038                charactersPerGlyph );
1039   }
1040
1041   const Length numberOfGlyphs = glyphs.Count();
1042
1043   if( GET_GLYPH_METRICS & operations )
1044   {
1045     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
1046   }
1047
1048   if( 0u != numberOfGlyphs )
1049   {
1050     // Create the glyph to character conversion table and the 'number of glyphs' per character.
1051     mImpl->mVisualModel->CreateCharacterToGlyphTable(numberOfCharacters );
1052     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
1053   }
1054 }
1055
1056 bool Controller::DoRelayout( const Vector2& size,
1057                              OperationsMask operationsRequired,
1058                              Size& layoutSize )
1059 {
1060   bool viewUpdated( false );
1061
1062   // Calculate the operations to be done.
1063   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1064
1065   if( LAYOUT & operations )
1066   {
1067     // Some vectors with data needed to layout and reorder may be void
1068     // after the first time the text has been laid out.
1069     // Fill the vectors again.
1070
1071     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
1072
1073     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1074     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1075     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1076     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1077     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1078
1079     // Set the layout parameters.
1080     LayoutParameters layoutParameters( size,
1081                                        mImpl->mLogicalModel->mText.Begin(),
1082                                        lineBreakInfo.Begin(),
1083                                        wordBreakInfo.Begin(),
1084                                        numberOfGlyphs,
1085                                        glyphs.Begin(),
1086                                        glyphsToCharactersMap.Begin(),
1087                                        charactersPerGlyph.Begin() );
1088
1089     // The laid-out lines.
1090     // It's not possible to know in how many lines the text is going to be laid-out,
1091     // but it can be resized at least with the number of 'paragraphs' to avoid
1092     // some re-allocations.
1093     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1094
1095     // Delete any previous laid out lines before setting the new ones.
1096     lines.Clear();
1097
1098     // The capacity of the bidirectional paragraph info is the number of paragraphs.
1099     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
1100
1101     // Resize the vector of positions to have the same size than the vector of glyphs.
1102     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1103     glyphPositions.Resize( numberOfGlyphs );
1104
1105     // Update the visual model.
1106     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1107                                                    glyphPositions,
1108                                                    lines,
1109                                                    layoutSize );
1110
1111     if( viewUpdated )
1112     {
1113       // Reorder the lines
1114       if( REORDER & operations )
1115       {
1116         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1117
1118         // Check first if there are paragraphs with bidirectional info.
1119         if( 0u != bidirectionalInfo.Count() )
1120         {
1121           // Get the lines
1122           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
1123
1124           // Reorder the lines.
1125           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1126           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1127           ReorderLines( bidirectionalInfo,
1128                         lines,
1129                         lineBidirectionalInfoRuns );
1130
1131           // Set the bidirectional info into the model.
1132           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1133           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1134                                                        numberOfBidirectionalInfoRuns );
1135
1136           // Set the bidirectional info per line into the layout parameters.
1137           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1138           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1139
1140           // Get the character to glyph conversion table and set into the layout.
1141           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1142
1143           // Get the glyphs per character table and set into the layout.
1144           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1145
1146           // Re-layout the text. Reorder those lines with right to left characters.
1147           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1148                                                          glyphPositions );
1149
1150           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1151           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1152                  endIt = lineBidirectionalInfoRuns.End();
1153                it != endIt;
1154                ++it )
1155           {
1156             BidirectionalLineInfoRun& bidiLineInfo = *it;
1157
1158             free( bidiLineInfo.visualToLogicalMap );
1159           }
1160         }
1161       } // REORDER
1162
1163       if( ALIGN & operations )
1164       {
1165         mImpl->mLayoutEngine.Align( layoutParameters,
1166                                     lines,
1167                                     glyphPositions );
1168       }
1169
1170       // Sets the actual size.
1171       if( UPDATE_ACTUAL_SIZE & operations )
1172       {
1173         mImpl->mVisualModel->SetActualSize( layoutSize );
1174       }
1175     } // view updated
1176   }
1177   else
1178   {
1179     layoutSize = mImpl->mVisualModel->GetActualSize();
1180   }
1181
1182   return viewUpdated;
1183 }
1184
1185 View& Controller::GetView()
1186 {
1187   return mImpl->mView;
1188 }
1189
1190 LayoutEngine& Controller::GetLayoutEngine()
1191 {
1192   return mImpl->mLayoutEngine;
1193 }
1194
1195 void Controller::RequestRelayout()
1196 {
1197   mImpl->mControlInterface.RequestTextRelayout();
1198 }
1199
1200 void Controller::KeyboardFocusGainEvent()
1201 {
1202   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1203
1204   if( mImpl->mTextInput )
1205   {
1206     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1207     mImpl->mTextInput->mEventQueue.push_back( event );
1208
1209     RequestRelayout();
1210   }
1211 }
1212
1213 void Controller::KeyboardFocusLostEvent()
1214 {
1215   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1216
1217   if( mImpl->mTextInput )
1218   {
1219     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1220     mImpl->mTextInput->mEventQueue.push_back( event );
1221
1222     RequestRelayout();
1223   }
1224 }
1225
1226 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1227 {
1228   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1229
1230   if( mImpl->mTextInput &&
1231       keyEvent.state == KeyEvent::Down )
1232   {
1233     int keyCode = keyEvent.keyCode;
1234     const std::string& keyString = keyEvent.keyPressed;
1235
1236     // Pre-process to separate modifying events from non-modifying input events.
1237     if( Dali::DALI_KEY_ESCAPE == keyCode )
1238     {
1239       // Escape key is a special case which causes focus loss
1240       KeyboardFocusLostEvent();
1241     }
1242     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1243              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1244              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1245              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1246     {
1247       TextInput::Event event( TextInput::CURSOR_KEY_EVENT );
1248       event.p1.mInt = keyCode;
1249       mImpl->mTextInput->mEventQueue.push_back( event );
1250     }
1251     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1252     {
1253       // Queue a delete event
1254       ModifyEvent event;
1255       event.type = DELETE_TEXT;
1256       mImpl->mModifyEvents.push_back( event );
1257     }
1258     else if( !keyString.empty() )
1259     {
1260       // Queue an insert event
1261       ModifyEvent event;
1262       event.type = INSERT_TEXT;
1263       event.text = keyString;
1264       mImpl->mModifyEvents.push_back( event );
1265     }
1266
1267     RequestRelayout();
1268   }
1269
1270   return false;
1271 }
1272
1273 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1274 {
1275   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1276
1277   if( mImpl->mTextInput )
1278   {
1279     TextInput::Event event( TextInput::TAP_EVENT );
1280     event.p1.mUint = tapCount;
1281     event.p2.mFloat = x;
1282     event.p3.mFloat = y;
1283     mImpl->mTextInput->mEventQueue.push_back( event );
1284
1285     RequestRelayout();
1286   }
1287 }
1288
1289 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1290 {
1291   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1292
1293   if( mImpl->mTextInput )
1294   {
1295     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1296     event.p1.mUint  = state;
1297     event.p2.mFloat = x;
1298     event.p3.mFloat = y;
1299     mImpl->mTextInput->mEventQueue.push_back( event );
1300
1301     RequestRelayout();
1302   }
1303 }
1304
1305 Controller::~Controller()
1306 {
1307   delete mImpl;
1308 }
1309
1310 Controller::Controller( ControlInterface& controlInterface )
1311 : mImpl( NULL )
1312 {
1313   mImpl = new Controller::Impl( controlInterface );
1314 }
1315
1316 } // namespace Text
1317
1318 } // namespace Toolkit
1319
1320 } // namespace Dali