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