60016d243a246723c5fe930e4eb03a505fc874a3
[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 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/text/character-set-conversion.h>
23 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
24 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
25 #include <dali-toolkit/internal/text/logical-model.h>
26 #include <dali-toolkit/internal/text/multi-language-support.h>
27 #include <dali-toolkit/internal/text/script-run.h>
28 #include <dali-toolkit/internal/text/segmentation.h>
29 #include <dali-toolkit/internal/text/shaper.h>
30 #include <dali-toolkit/internal/text/text-view.h>
31 #include <dali-toolkit/internal/text/visual-model.h>
32
33 // EXTERNAL INCLUDES
34 #include <limits>
35 #include <vector>
36 #include <dali/public-api/adaptor-framework/key.h>
37 #include <dali/public-api/text-abstraction/font-client.h>
38
39 using std::vector;
40
41 namespace Dali
42 {
43
44 namespace Toolkit
45 {
46
47 namespace Text
48 {
49
50 struct Controller::TextInput
51 {
52   // Used to queue input events until DoRelayout()
53   enum EventType
54   {
55     KEYBOARD_FOCUS_GAIN_EVENT,
56     KEYBOARD_FOCUS_LOST_EVENT,
57     KEY_EVENT,
58     TAP_EVENT,
59     GRAB_HANDLE_EVENT
60   };
61
62   union Param
63   {
64     int mInt;
65     unsigned int mUint;
66     float mFloat;
67     char* mString;
68   };
69
70   struct Event
71   {
72     Event( EventType eventType )
73     : type( eventType )
74     {
75       p1.mInt = 0;
76       p2.mInt = 0;
77     }
78
79     EventType type;
80     Param p1;
81     Param p2;
82     Param p3;
83   };
84
85   enum State
86   {
87     INACTIVE,
88     SELECTING,
89     EDITING
90   };
91
92   TextInput( LogicalModelPtr logicalModel,
93              VisualModelPtr visualModel,
94              DecoratorPtr decorator )
95   : mLogicalModel( logicalModel ),
96     mVisualModel( visualModel ),
97     mDecorator( decorator ),
98     mState( INACTIVE )
99   {
100   }
101
102   /**
103    * @brief Helper to move the cursor, grab handle etc.
104    */
105   bool ProcessInputEvents()
106   {
107     mDecoratorUpdated = false;
108
109     if( mDecorator )
110     {
111       for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
112       {
113         switch( iter->type )
114         {
115           case KEYBOARD_FOCUS_GAIN_EVENT:
116           {
117             OnKeyboardFocus( true );
118             break;
119           }
120           case KEYBOARD_FOCUS_LOST_EVENT:
121           {
122             OnKeyboardFocus( false );
123             break;
124           }
125           case KEY_EVENT:
126           {
127             OnKeyEvent( *iter );
128             break;
129           }
130           case TAP_EVENT:
131           {
132             OnTapEvent( *iter );
133             break;
134           }
135           case GRAB_HANDLE_EVENT:
136           {
137             OnGrabHandleEvent( *iter );
138             break;
139           }
140         }
141       }
142     }
143
144     mEventQueue.clear();
145
146     return mDecoratorUpdated;
147   }
148
149   void OnKeyboardFocus( bool hasFocus )
150   {
151   }
152
153   void OnKeyEvent( const Event& event )
154   {
155     int keyCode = event.p1.mInt;
156
157     // Handle state changes
158     if( Dali::DALI_KEY_ESCAPE == keyCode )
159     {
160       ChangeState( INACTIVE ); // Escape key ends edit mode
161     }
162     else if ( event.p2.mString )
163     {
164       // Some text may be selected, hiding keyboard causes an empty keystring to be sent, we don't want to delete highlight in this case
165       ChangeState( EDITING );
166     }
167
168     // Handle the actual key event
169     if( Dali::DALI_KEY_BACKSPACE == keyCode )
170     {
171       HandleBackspaceKey();
172     }
173     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
174              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
175              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
176              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
177     {
178       HandleCursorKey( keyCode );
179     }
180     else if ( event.p2.mString )
181     {
182       HandleKeyString( event.p2.mString );
183
184       delete [] event.p2.mString;
185     }
186   }
187
188   void HandleBackspaceKey()
189   {
190     // TODO
191   }
192
193   void HandleCursorKey( int keyCode )
194   {
195     // TODO
196   }
197
198   void HandleKeyString( const char* keyString )
199   {
200     // TODO
201   }
202
203   void OnTapEvent( const Event& event )
204   {
205     unsigned int tapCount = event.p1.mUint;
206
207     if( 1u == tapCount )
208     {
209       ChangeState( EDITING );
210
211       float xPosition = event.p2.mFloat;
212       float yPosition = event.p3.mFloat;
213       float height(0.0f);
214       GetClosestCursorPosition( xPosition, yPosition, height );
215       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
216
217       mDecoratorUpdated = true;
218     }
219     else if( 2u == tapCount )
220     {
221       ChangeState( SELECTING );
222     }
223   }
224
225   void OnGrabHandleEvent( const Event& event )
226   {
227     unsigned int state = event.p1.mUint;
228
229     if( GRAB_HANDLE_PRESSED == state )
230     {
231       float xPosition = event.p2.mFloat;
232       float yPosition = event.p3.mFloat;
233       float height(0.0f);
234
235       GetClosestCursorPosition( xPosition, yPosition, height );
236
237       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
238       mDecoratorUpdated = true;
239     }
240   }
241
242   void ChangeState( State newState )
243   {
244     if( mState != newState )
245     {
246       mState = newState;
247
248       if( INACTIVE == mState )
249       {
250         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
251         mDecorator->StopCursorBlink();
252         mDecorator->SetGrabHandleActive( false );
253         mDecorator->SetSelectionActive( false );
254         mDecoratorUpdated = true;
255       }
256       else if ( SELECTING == mState )
257       {
258         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
259         mDecorator->StopCursorBlink();
260         mDecorator->SetGrabHandleActive( false );
261         mDecorator->SetSelectionActive( true );
262         mDecoratorUpdated = true;
263       }
264       else if( EDITING == mState )
265       {
266         mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
267         mDecorator->StartCursorBlink();
268         mDecorator->SetGrabHandleActive( true );
269         mDecorator->SetSelectionActive( false );
270         mDecoratorUpdated = true;
271       }
272     }
273   }
274
275   void GetClosestCursorPosition( float& x, float& y, float& height )
276   {
277     // TODO - Look at LineRuns first
278
279     Text::Length numberOfGlyphs = mVisualModel->GetNumberOfGlyphs();
280     if( 0 == numberOfGlyphs )
281     {
282       return;
283     }
284
285     Vector<GlyphInfo> glyphs;
286     glyphs.Resize( numberOfGlyphs );
287     mVisualModel->GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
288
289     std::vector<Vector2> positions;
290     positions.resize( numberOfGlyphs );
291     mVisualModel->GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
292
293     unsigned int closestGlyph = 0;
294     float closestDistance = std::numeric_limits<float>::max();
295
296     for( unsigned int i=0; i<glyphs.Count(); ++i )
297     {
298       float glyphX = positions[i].x + glyphs[i].width*0.5f;
299       float glyphY = positions[i].y + glyphs[i].height*0.5f;
300
301       float distanceToGlyph = fabsf( glyphX - x ) + fabsf( glyphY - y );
302
303       if( distanceToGlyph < closestDistance )
304       {
305         closestDistance = distanceToGlyph;
306         closestGlyph = i;
307       }
308     }
309
310     // TODO - Consider RTL languages
311     x = positions[closestGlyph].x + glyphs[closestGlyph].width;
312     y = 0.0f;
313
314     FontMetrics metrics;
315     TextAbstraction::FontClient::Get().GetFontMetrics( glyphs[closestGlyph].fontId, metrics );
316     height = metrics.height; // TODO - Fix for multi-line
317   }
318
319   LogicalModelPtr mLogicalModel;
320   VisualModelPtr  mVisualModel;
321   DecoratorPtr    mDecorator;
322
323   std::string mPlaceholderText;
324
325   /**
326    * This is used to delay handling events until after the model has been updated.
327    * The number of updates to the model is minimized to improve performance.
328    */
329   vector<Event> mEventQueue; ///< The queue of touch events etc.
330
331   State mState;
332
333   bool mDecoratorUpdated;
334 };
335
336 struct Controller::FontDefaults
337 {
338   FontDefaults()
339   : mDefaultPointSize(0.0f),
340     mFontId(0u)
341   {
342   }
343
344   FontId GetFontId( TextAbstraction::FontClient& fontClient )
345   {
346     if( !mFontId )
347     {
348       Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
349       mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
350     }
351
352     return mFontId;
353   }
354
355   std::string mDefaultFontFamily;
356   std::string mDefaultFontStyle;
357   float mDefaultPointSize;
358   FontId mFontId;
359 };
360
361 struct Controller::Impl
362 {
363   Impl( ControlInterface& controlInterface )
364   : mControlInterface( controlInterface ),
365     mNewText(),
366     mOperations( NO_OPERATION ),
367     mControlSize(),
368     mFontDefaults( NULL ),
369     mTextInput( NULL )
370   {
371     mLogicalModel = LogicalModel::New();
372     mVisualModel  = VisualModel::New();
373
374     mView.SetVisualModel( mVisualModel );
375
376     mFontClient = TextAbstraction::FontClient::Get();
377   }
378
379   ~Impl()
380   {
381     delete mTextInput;
382   }
383
384   ControlInterface& mControlInterface;
385
386   std::string mNewText;
387
388   LogicalModelPtr mLogicalModel;
389   VisualModelPtr  mVisualModel;
390
391   View mView;
392
393   LayoutEngine mLayoutEngine;
394
395   TextAbstraction::FontClient mFontClient;
396
397   OperationsMask mOperations;
398
399   Size mControlSize;
400
401   // Avoid allocating this when the user does not specify a font
402   FontDefaults* mFontDefaults;
403
404   // Avoid allocating everything for text input until EnableTextInput()
405   Controller::TextInput* mTextInput;
406 };
407
408 ControllerPtr Controller::New( ControlInterface& controlInterface )
409 {
410   return ControllerPtr( new Controller( controlInterface ) );
411 }
412
413 void Controller::SetText( const std::string& text )
414 {
415   // Keep until size negotiation
416   mImpl->mNewText = text;
417   mImpl->mOperations = ALL_OPERATIONS;
418
419   if( mImpl->mTextInput )
420   {
421     // Cancel previously queued events
422     mImpl->mTextInput->mEventQueue.clear();
423
424     // TODO - Hide selection decorations
425   }
426 }
427
428 void Controller::GetText( std::string& text ) const
429 {
430   if( !mImpl->mNewText.empty() )
431   {
432     text = mImpl->mNewText;
433   }
434   else
435   {
436     // TODO - Convert from UTF-32
437   }
438 }
439
440 void Controller::SetPlaceholderText( const std::string& text )
441 {
442   if( !mImpl->mTextInput )
443   {
444     mImpl->mTextInput->mPlaceholderText = text;
445   }
446 }
447
448 void Controller::GetPlaceholderText( std::string& text ) const
449 {
450   if( !mImpl->mTextInput )
451   {
452     text = mImpl->mTextInput->mPlaceholderText;
453   }
454 }
455
456 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
457 {
458   if( !mImpl->mFontDefaults )
459   {
460     mImpl->mFontDefaults = new Controller::FontDefaults();
461   }
462
463   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
464   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
465   mImpl->mOperations = ALL_OPERATIONS;
466 }
467
468 const std::string& Controller::GetDefaultFontFamily() const
469 {
470   if( mImpl->mFontDefaults )
471   {
472     return mImpl->mFontDefaults->mDefaultFontFamily;
473   }
474
475   return Dali::String::EMPTY;
476 }
477
478 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
479 {
480   if( !mImpl->mFontDefaults )
481   {
482     mImpl->mFontDefaults = new Controller::FontDefaults();
483   }
484
485   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
486   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
487   mImpl->mOperations = ALL_OPERATIONS;
488 }
489
490 const std::string& Controller::GetDefaultFontStyle() const
491 {
492   if( mImpl->mFontDefaults )
493   {
494     return mImpl->mFontDefaults->mDefaultFontStyle;
495   }
496
497   return Dali::String::EMPTY;
498 }
499
500 void Controller::SetDefaultPointSize( float pointSize )
501 {
502   if( !mImpl->mFontDefaults )
503   {
504     mImpl->mFontDefaults = new Controller::FontDefaults();
505   }
506
507   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
508   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
509   mImpl->mOperations = ALL_OPERATIONS;
510 }
511
512 float Controller::GetDefaultPointSize() const
513 {
514   if( mImpl->mFontDefaults )
515   {
516     return mImpl->mFontDefaults->mDefaultPointSize;
517   }
518
519   return 0.0f;
520 }
521
522 void Controller::EnableTextInput( DecoratorPtr decorator )
523 {
524   if( !mImpl->mTextInput )
525   {
526     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
527   }
528 }
529
530 bool Controller::Relayout( const Vector2& size )
531 {
532   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
533   {
534     // Not worth to relayout if width or height is equal to zero.
535     return false;
536   }
537
538   bool updated = false;
539
540   if( size != mImpl->mControlSize )
541   {
542     updated = DoRelayout( size, mImpl->mOperations );
543
544     // Do not re-do any operation until something changes.
545     mImpl->mOperations = NO_OPERATION;
546
547     mImpl->mControlSize = size;
548   }
549
550   if( mImpl->mTextInput )
551   {
552     // Move the cursor, grab handle etc.
553     updated = mImpl->mTextInput->ProcessInputEvents() || updated;
554   }
555
556   return updated;
557 }
558
559 bool Controller::DoRelayout( const Vector2& size, OperationsMask operations )
560 {
561   bool viewUpdated( false );
562
563   Vector<Character> utf32Characters;
564   Length characterCount = 0u;
565   if( CONVERT_TO_UTF32 & operations )
566   {
567     std::string& text = mImpl->mNewText;
568
569     //  Convert text into UTF-32
570     utf32Characters.Resize( text.size() );
571
572     // This is a bit horrible but std::string returns a (signed) char*
573     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
574
575     // Transform a text array encoded in utf8 into an array encoded in utf32.
576     // It returns the actual number of characters.
577     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
578     utf32Characters.Resize( characterCount );
579
580     // Sets the text into the model.
581     mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
582
583     // Discard temporary text
584     //text.clear(); temporary keep the text. will be fixed in the next patch.
585   }
586
587   Vector<LineBreakInfo> lineBreakInfo;
588   if( GET_LINE_BREAKS & operations )
589   {
590     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
591     // calculate the bidirectional info for each 'paragraph'.
592     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
593     // is not shaped together).
594     lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
595
596     SetLineBreakInfo( utf32Characters,
597                       lineBreakInfo );
598
599     mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
600   }
601
602   Vector<WordBreakInfo> wordBreakInfo;
603   if( GET_WORD_BREAKS & operations )
604   {
605     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
606     wordBreakInfo.Resize( characterCount, TextAbstraction::WORD_NO_BREAK );
607
608     SetWordBreakInfo( utf32Characters,
609                       wordBreakInfo );
610
611     mImpl->mLogicalModel->SetWordBreakInfo( wordBreakInfo.Begin(), characterCount );
612   }
613
614   const bool getScripts = GET_SCRIPTS & operations;
615   const bool validateFonts = VALIDATE_FONTS & operations;
616
617   Vector<ScriptRun> scripts;
618   Vector<FontRun> fonts;
619
620   if( mImpl->mFontDefaults )
621   {
622     // TODO - pass into ValidateFonts
623   }
624
625   if( getScripts || validateFonts )
626   {
627     // Validates the fonts assigned by the application or assigns default ones.
628     // It makes sure all the characters are going to be rendered by the correct font.
629     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
630
631     if( getScripts )
632     {
633       // Retrieves the scripts used in the text.
634       multilanguageSupport.SetScripts( utf32Characters,
635                                        lineBreakInfo,
636                                        scripts );
637
638       // Sets the scripts into the model.
639       mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
640     }
641
642     if( validateFonts )
643     {
644       // Validates the fonts. If there is a character with no assigned font it sets a default one.
645       // After this call, fonts are validated.
646       multilanguageSupport.ValidateFonts( utf32Characters,
647                                           scripts,
648                                           fonts );
649
650       // Sets the fonts into the model.
651       mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() );
652     }
653   }
654
655   Vector<GlyphInfo> glyphs;
656   Vector<CharacterIndex> glyphsToCharactersMap;
657   Vector<Length> charactersPerGlyph;
658   if( SHAPE_TEXT & operations )
659   {
660     // Shapes the text.
661     ShapeText( utf32Characters,
662                lineBreakInfo,
663                scripts,
664                fonts,
665                glyphs,
666                glyphsToCharactersMap,
667                charactersPerGlyph );
668   }
669
670   if( GET_GLYPH_METRICS & operations )
671   {
672     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
673   }
674
675   Length numberOfGlyphs = glyphs.Count();
676   if( 0u != numberOfGlyphs )
677   {
678     // Sets the glyphs into the model.
679     mImpl->mVisualModel->SetGlyphs( glyphs.Begin(),
680                                     glyphsToCharactersMap.Begin(),
681                                     charactersPerGlyph.Begin(),
682                                     numberOfGlyphs );
683   }
684
685   if( LAYOUT & operations )
686   {
687     if( 0u == numberOfGlyphs )
688     {
689       const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
690       numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
691
692       lineBreakInfo.Resize( numberOfCharacters );
693       wordBreakInfo.Resize( numberOfCharacters );
694       glyphs.Resize( numberOfGlyphs );
695       glyphsToCharactersMap.Resize( numberOfGlyphs );
696       charactersPerGlyph.Resize( numberOfGlyphs );
697
698       mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
699                                               0u,
700                                               numberOfCharacters );
701
702       mImpl->mLogicalModel->GetWordBreakInfo( wordBreakInfo.Begin(),
703                                               0u,
704                                               numberOfCharacters );
705
706       mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
707                                       0u,
708                                       numberOfGlyphs );
709
710       mImpl->mVisualModel->GetGlyphToCharacterMap( glyphsToCharactersMap.Begin(),
711                                                    0u,
712                                                    numberOfGlyphs );
713
714       mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
715                                                      0u,
716                                                      numberOfGlyphs );
717     }
718
719     // Set the layout parameters.
720     LayoutParameters layoutParameters( size,
721                                        lineBreakInfo.Begin(),
722                                        wordBreakInfo.Begin(),
723                                        numberOfGlyphs,
724                                        glyphs.Begin(),
725                                        glyphsToCharactersMap.Begin(),
726                                        charactersPerGlyph.Begin() );
727
728     // Reserve space to set the positions of the glyphs.
729     Vector<Vector2> glyphPositions;
730     glyphPositions.Resize( numberOfGlyphs );
731
732     Size layoutSize;
733
734     // Update the visual model
735     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
736                                                    glyphPositions,
737                                                    layoutSize );
738
739     // Sets the positions into the model.
740     mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(),
741                                             numberOfGlyphs );
742
743     // Sets the actual size.
744     mImpl->mVisualModel->SetActualSize( layoutSize );
745   }
746
747   return viewUpdated;
748 }
749
750 Vector3 Controller::GetNaturalSize()
751 {
752   // TODO - Finish implementing
753   return Vector3::ZERO;
754
755   // Operations that can be done only once until the text changes.
756   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
757                                                                          GET_SCRIPTS      |
758                                                                          VALIDATE_FONTS   |
759                                                                          GET_LINE_BREAKS  |
760                                                                          GET_WORD_BREAKS  |
761                                                                          SHAPE_TEXT       |
762                                                                          GET_GLYPH_METRICS );
763
764   // Operations that need to be done if the size or the text changes.
765   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
766                                                                       REORDER );
767
768   const float maxFloat = std::numeric_limits<float>::max();
769   DoRelayout( Vector2( maxFloat, maxFloat ),
770               static_cast<OperationsMask>( onlyOnceOperations |
771                                            sizeOperations ) );
772
773   // Do not do again the only once operations.
774   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
775
776   // Do the size related operations again.
777   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
778
779   return Vector3( mImpl->mVisualModel->GetNaturalSize() );
780 }
781
782 float Controller::GetHeightForWidth( float width )
783 {
784   // Operations that can be done only once until the text changes.
785   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
786                                                                          GET_SCRIPTS      |
787                                                                          VALIDATE_FONTS   |
788                                                                          GET_LINE_BREAKS  |
789                                                                          GET_WORD_BREAKS  |
790                                                                          SHAPE_TEXT       |
791                                                                          GET_GLYPH_METRICS );
792
793   // Operations that need to be done if the size or the text changes.
794   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
795                                                                       REORDER );
796
797   DoRelayout( Size( width, 0.f ),
798               static_cast<OperationsMask>( onlyOnceOperations |
799                                            sizeOperations ) );
800
801   // Do not do again the only once operations.
802   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
803
804   // Do the size related operations again.
805   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
806
807   return mImpl->mVisualModel->GetActualSize().height;
808 }
809
810 View& Controller::GetView()
811 {
812   return mImpl->mView;
813 }
814
815 LayoutEngine& Controller::GetLayoutEngine()
816 {
817   return mImpl->mLayoutEngine;
818 }
819
820 void Controller::RequestRelayout()
821 {
822   mImpl->mControlInterface.RequestTextRelayout();
823 }
824
825 void Controller::KeyboardFocusGainEvent()
826 {
827   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
828
829   if( mImpl->mTextInput )
830   {
831     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
832     mImpl->mTextInput->mEventQueue.push_back( event );
833
834     RequestRelayout();
835   }
836 }
837
838 void Controller::KeyboardFocusLostEvent()
839 {
840   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
841
842   if( mImpl->mTextInput )
843   {
844     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
845     mImpl->mTextInput->mEventQueue.push_back( event );
846
847     RequestRelayout();
848   }
849 }
850
851 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
852 {
853   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
854
855   if( mImpl->mTextInput )
856   {
857     TextInput::Event event( TextInput::KEY_EVENT );
858     event.p1.mInt = keyEvent.keyCode;
859     event.p2.mString = NULL;
860
861     const std::string& keyString = keyEvent.keyPressed;
862     if ( !keyString.empty() )
863     {
864       event.p2.mString = new char[keyString.size() + 1];
865       std::copy(keyString.begin(), keyString.end(), event.p2.mString);
866       event.p2.mString[keyString.size()] = '\0';
867     }
868
869     mImpl->mTextInput->mEventQueue.push_back( event );
870
871     RequestRelayout();
872   }
873
874   return false;
875 }
876
877 void Controller::TapEvent( unsigned int tapCount, float x, float y )
878 {
879   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
880
881   if( mImpl->mTextInput )
882   {
883     TextInput::Event event( TextInput::TAP_EVENT );
884     event.p1.mUint = tapCount;
885     event.p2.mFloat = x;
886     event.p3.mFloat = y;
887     mImpl->mTextInput->mEventQueue.push_back( event );
888
889     RequestRelayout();
890   }
891 }
892
893 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
894 {
895   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
896
897   if( mImpl->mTextInput )
898   {
899     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
900     event.p1.mUint  = state;
901     event.p2.mFloat = x;
902     event.p3.mFloat = y;
903     mImpl->mTextInput->mEventQueue.push_back( event );
904
905     RequestRelayout();
906   }
907 }
908
909 Controller::~Controller()
910 {
911   delete mImpl;
912 }
913
914 Controller::Controller( ControlInterface& controlInterface )
915 : mImpl( NULL )
916 {
917   mImpl = new Controller::Impl( controlInterface );
918 }
919
920 } // namespace Text
921
922 } // namespace Toolkit
923
924 } // namespace Dali