Break-up the Relayout method
[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   // Make sure the model is up-to-date before layouting
647   ReplaceText( mImpl->mOperationsPending );
648
649   Size layoutSize;
650   bool updated = DoRelayout( mImpl->mControlSize,
651                              mImpl->mOperationsPending,
652                              layoutSize );
653
654   // Do not re-do any operation until something changes.
655   mImpl->mOperationsPending = NO_OPERATION;
656
657   if( mImpl->mTextInput )
658   {
659     // Move the cursor, grab handle etc.
660     updated = mImpl->mTextInput->ProcessInputEvents() || updated;
661   }
662
663   return updated;
664 }
665
666 void Controller::ReplaceText( OperationsMask operationsRequired )
667 {
668   // Calculate the operations to be done.
669   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
670
671   Vector<Character> utf32Characters;
672   Length characterCount = 0u;
673   if( CONVERT_TO_UTF32 & operations )
674   {
675     std::string& text = mImpl->mNewText;
676
677     //  Convert text into UTF-32
678     utf32Characters.Resize( text.size() );
679
680     // This is a bit horrible but std::string returns a (signed) char*
681     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
682
683     // Transform a text array encoded in utf8 into an array encoded in utf32.
684     // It returns the actual number of characters.
685     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
686     utf32Characters.Resize( characterCount );
687
688     // Sets the text into the model.
689     mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
690
691     // Discard temporary text
692     text.clear();
693   }
694
695   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
696
697   Vector<LineBreakInfo> lineBreakInfo;
698   if( GET_LINE_BREAKS & operations )
699   {
700     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
701     // calculate the bidirectional info for each 'paragraph'.
702     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
703     // is not shaped together).
704     lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
705
706     SetLineBreakInfo( utf32Characters,
707                       lineBreakInfo );
708
709     mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
710   }
711
712   Vector<WordBreakInfo> wordBreakInfo;
713   if( GET_WORD_BREAKS & operations )
714   {
715     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
716     wordBreakInfo.Resize( characterCount, TextAbstraction::WORD_NO_BREAK );
717
718     SetWordBreakInfo( utf32Characters,
719                       wordBreakInfo );
720
721     mImpl->mLogicalModel->SetWordBreakInfo( wordBreakInfo.Begin(), characterCount );
722   }
723
724   const bool getScripts = GET_SCRIPTS & operations;
725   const bool validateFonts = VALIDATE_FONTS & operations;
726
727   Vector<ScriptRun> scripts;
728   Vector<FontRun> validFonts;
729
730   if( getScripts || validateFonts )
731   {
732     // Validates the fonts assigned by the application or assigns default ones.
733     // It makes sure all the characters are going to be rendered by the correct font.
734     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
735
736     if( getScripts )
737     {
738       // Retrieves the scripts used in the text.
739       multilanguageSupport.SetScripts( utf32Characters,
740                                        lineBreakInfo,
741                                        scripts );
742
743       // Sets the scripts into the model.
744       mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
745     }
746
747     if( validateFonts )
748     {
749       // Copy the requested font defaults received via the property system.
750       // These may not be valid i.e. may not contain glyphs for the necessary scripts.
751       GetDefaultFonts( validFonts, numberOfCharacters );
752
753       // Validates the fonts. If there is a character with no assigned font it sets a default one.
754       // After this call, fonts are validated.
755       multilanguageSupport.ValidateFonts( utf32Characters,
756                                           scripts,
757                                           validFonts );
758
759       // Sets the fonts into the model.
760       mImpl->mLogicalModel->SetFonts( validFonts.Begin(), validFonts.Count() );
761     }
762   }
763
764   if( BIDI_INFO & operations )
765   {
766     // Some vectors with data needed to get the paragraph's bidirectional info may be void
767     // after the first time the text has been laid out.
768     // Fill the vectors again.
769
770     if( 0u == utf32Characters.Count() )
771     {
772       utf32Characters.Resize( numberOfCharacters );
773
774       mImpl->mLogicalModel->GetText( utf32Characters.Begin(),
775                                      0u,
776                                      numberOfCharacters );
777     }
778
779     if( 0u == lineBreakInfo.Count() )
780     {
781       lineBreakInfo.Resize( numberOfCharacters );
782
783       mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
784                                               0u,
785                                               numberOfCharacters );
786     }
787
788     if( 0u == scripts.Count() )
789     {
790       scripts.Resize( mImpl->mLogicalModel->GetNumberOfScriptRuns( 0u,
791                                                                    numberOfCharacters ) );
792       mImpl->mLogicalModel->GetScriptRuns( scripts.Begin(),
793                                            0u,
794                                            numberOfCharacters );
795     }
796
797     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
798     // bidirectional info.
799
800     Length numberOfParagraphs = 0u;
801
802     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
803     for( Length index = 0u; index < characterCount; ++index )
804     {
805       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
806       {
807         ++numberOfParagraphs;
808       }
809     }
810
811     Vector<BidirectionalParagraphInfoRun> bidirectionalInfo;
812     bidirectionalInfo.Reserve( numberOfParagraphs );
813
814     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
815     SetBidirectionalInfo( utf32Characters,
816                           scripts,
817                           lineBreakInfo,
818                           bidirectionalInfo );
819
820     mImpl->mLogicalModel->SetBidirectionalInfo( bidirectionalInfo.Begin(),
821                                                 bidirectionalInfo.Count() );
822   }
823
824   Vector<GlyphInfo> glyphs;
825   Vector<CharacterIndex> glyphsToCharactersMap;
826   Vector<Length> charactersPerGlyph;
827   if( SHAPE_TEXT & operations )
828   {
829     if( 0u == validFonts.Count() )
830     {
831       validFonts.Resize( mImpl->mLogicalModel->GetNumberOfFontRuns( 0u,
832                                                                     numberOfCharacters ) );
833       mImpl->mLogicalModel->GetFontRuns( validFonts.Begin(),
834                                          0u,
835                                          numberOfCharacters );
836     }
837
838     // Shapes the text.
839     ShapeText( utf32Characters,
840                lineBreakInfo,
841                scripts,
842                validFonts,
843                glyphs,
844                glyphsToCharactersMap,
845                charactersPerGlyph );
846   }
847
848   if( GET_GLYPH_METRICS & operations )
849   {
850     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
851   }
852
853   Length numberOfGlyphs = glyphs.Count();
854   if( 0u != numberOfGlyphs )
855   {
856     // Sets the glyphs into the model.
857     mImpl->mVisualModel->SetGlyphs( glyphs.Begin(),
858                                     glyphsToCharactersMap.Begin(),
859                                     charactersPerGlyph.Begin(),
860                                     numberOfGlyphs );
861   }
862 }
863
864 bool Controller::DoRelayout( const Vector2& size,
865                              OperationsMask operationsRequired,
866                              Size& layoutSize )
867 {
868   bool viewUpdated( false );
869
870   // Calculate the operations to be done.
871   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
872
873   if( LAYOUT & operations )
874   {
875     // Some vectors with data needed to layout and reorder may be void
876     // after the first time the text has been laid out.
877     // Fill the vectors again.
878
879     const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
880     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
881
882     Vector<LineBreakInfo> lineBreakInfo;
883     lineBreakInfo.Resize( numberOfCharacters );
884     mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
885                                             0u,
886                                             numberOfCharacters );
887
888     Vector<WordBreakInfo> wordBreakInfo;
889     wordBreakInfo.Resize( numberOfCharacters );
890     mImpl->mLogicalModel->GetWordBreakInfo( wordBreakInfo.Begin(),
891                                             0u,
892                                             numberOfCharacters );
893
894     Vector<GlyphInfo> glyphs;
895     glyphs.Resize( numberOfGlyphs );
896     mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
897                                     0u,
898                                     numberOfGlyphs );
899
900     Vector<CharacterIndex> glyphsToCharactersMap;
901     glyphsToCharactersMap.Resize( numberOfGlyphs );
902     mImpl->mVisualModel->GetGlyphToCharacterMap( glyphsToCharactersMap.Begin(),
903                                                  0u,
904                                                  numberOfGlyphs );
905
906     Vector<Length> charactersPerGlyph;
907     charactersPerGlyph.Resize( numberOfGlyphs );
908     mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
909                                                    0u,
910                                                    numberOfGlyphs );
911
912     // Set the layout parameters.
913     LayoutParameters layoutParameters( size,
914                                        lineBreakInfo.Begin(),
915                                        wordBreakInfo.Begin(),
916                                        numberOfGlyphs,
917                                        glyphs.Begin(),
918                                        glyphsToCharactersMap.Begin(),
919                                        charactersPerGlyph.Begin() );
920
921     // Reserve space to set the positions of the glyphs.
922     Vector<Vector2> glyphPositions;
923     glyphPositions.Resize( numberOfGlyphs );
924
925     // The laid-out lines.
926     // It's not possible to know in how many lines the text is going to be laid-out,
927     // but it can be resized at least with the number of 'paragraphs' to avoid
928     // some re-allocations.
929     Vector<LineRun> lines;
930     lines.Reserve( mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters ) );
931
932     // Update the visual model.
933     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
934                                                    glyphPositions,
935                                                    lines,
936                                                    layoutSize );
937
938     if( viewUpdated )
939     {
940       // Reorder the lines
941       if( REORDER & operations )
942       {
943         const Length numberOfBidiParagraphs = mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters );
944
945         Vector<BidirectionalParagraphInfoRun> bidirectionalInfo;
946         bidirectionalInfo.Resize( numberOfBidiParagraphs );
947         mImpl->mLogicalModel->GetBidirectionalInfo( bidirectionalInfo.Begin(),
948                                                     0u,
949                                                     numberOfCharacters );
950
951         // Check first if there are paragraphs with bidirectional info.
952         if( 0u != bidirectionalInfo.Count() )
953         {
954           // Get the lines
955           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
956
957           // Reorder the lines.
958           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
959           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
960           ReorderLines( bidirectionalInfo,
961                         lines,
962                         lineBidirectionalInfoRuns );
963
964           // Set the bidirectional info into the model.
965           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
966           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
967                                                        numberOfBidirectionalInfoRuns );
968
969           // Set the bidirectional info per line into the layout parameters.
970           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
971           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
972
973           // Get the character to glyph conversion table and set into the layout.
974           Vector<GlyphIndex> characterToGlyphMap;
975           characterToGlyphMap.Resize( numberOfCharacters );
976
977           layoutParameters.charactersToGlyphsBuffer = characterToGlyphMap.Begin();
978           mImpl->mVisualModel->GetCharacterToGlyphMap( layoutParameters.charactersToGlyphsBuffer,
979                                                        0u,
980                                                        numberOfCharacters );
981
982           // Get the glyphs per character table and set into the layout.
983           Vector<Length> glyphsPerCharacter;
984           glyphsPerCharacter.Resize( numberOfCharacters );
985
986           layoutParameters.glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
987           mImpl->mVisualModel->GetGlyphsPerCharacterMap( layoutParameters.glyphsPerCharacterBuffer,
988                                                          0u,
989                                                          numberOfCharacters );
990
991           // Re-layout the text. Reorder those lines with right to left characters.
992           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
993                                                          glyphPositions );
994
995           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
996           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
997                  endIt = lineBidirectionalInfoRuns.End();
998                it != endIt;
999                ++it )
1000           {
1001             BidirectionalLineInfoRun& bidiLineInfo = *it;
1002
1003             free( bidiLineInfo.visualToLogicalMap );
1004           }
1005         }
1006       }
1007
1008       // Sets the positions into the model.
1009       if( UPDATE_POSITIONS & operations )
1010       {
1011         mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(),
1012                                                 numberOfGlyphs );
1013       }
1014
1015       // Sets the lines into the model.
1016       if( UPDATE_LINES & operations )
1017       {
1018         mImpl->mVisualModel->SetLines( lines.Begin(),
1019                                        lines.Count() );
1020       }
1021
1022       // Sets the actual size.
1023       if( UPDATE_ACTUAL_SIZE & operations )
1024       {
1025         mImpl->mVisualModel->SetActualSize( layoutSize );
1026       }
1027     }
1028   }
1029   else
1030   {
1031     layoutSize = mImpl->mVisualModel->GetActualSize();
1032   }
1033
1034   return viewUpdated;
1035 }
1036
1037 Vector3 Controller::GetNaturalSize()
1038 {
1039   Vector3 naturalSize;
1040
1041   if( mImpl->mRecalculateNaturalSize )
1042   {
1043     // Operations that can be done only once until the text changes.
1044     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1045                                                                            GET_SCRIPTS       |
1046                                                                            VALIDATE_FONTS    |
1047                                                                            GET_LINE_BREAKS   |
1048                                                                            GET_WORD_BREAKS   |
1049                                                                            SHAPE_TEXT        |
1050                                                                            GET_GLYPH_METRICS );
1051     // Make sure the model is up-to-date before layouting
1052     ReplaceText( onlyOnceOperations );
1053
1054     // Operations that need to be done if the size changes.
1055     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1056                                                                         REORDER );
1057
1058     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1059                 static_cast<OperationsMask>( onlyOnceOperations |
1060                                              sizeOperations ),
1061                 naturalSize.GetVectorXY() );
1062
1063     // Do not do again the only once operations.
1064     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1065
1066     // Do the size related operations again.
1067     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1068
1069     // Stores the natural size to avoid recalculate it again
1070     // unless the text/style changes.
1071     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1072
1073     mImpl->mRecalculateNaturalSize = false;
1074   }
1075   else
1076   {
1077     naturalSize = mImpl->mVisualModel->GetNaturalSize();
1078   }
1079
1080   return naturalSize;
1081 }
1082
1083 float Controller::GetHeightForWidth( float width )
1084 {
1085   Size layoutSize;
1086   if( width != mImpl->mControlSize.width )
1087   {
1088     // Operations that can be done only once until the text changes.
1089     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1090                                                                            GET_SCRIPTS       |
1091                                                                            VALIDATE_FONTS    |
1092                                                                            GET_LINE_BREAKS   |
1093                                                                            GET_WORD_BREAKS   |
1094                                                                            SHAPE_TEXT        |
1095                                                                            GET_GLYPH_METRICS );
1096
1097     // Make sure the model is up-to-date before layouting
1098     ReplaceText( onlyOnceOperations );
1099
1100     // Operations that need to be done if the size changes.
1101     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1102                                                                         REORDER );
1103
1104     DoRelayout( Size( width, MAX_FLOAT ),
1105                 static_cast<OperationsMask>( onlyOnceOperations |
1106                                              sizeOperations ),
1107                 layoutSize );
1108
1109     // Do not do again the only once operations.
1110     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1111
1112     // Do the size related operations again.
1113     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1114   }
1115   else
1116   {
1117     layoutSize = mImpl->mVisualModel->GetActualSize();
1118   }
1119
1120   return layoutSize.height;
1121 }
1122
1123 View& Controller::GetView()
1124 {
1125   return mImpl->mView;
1126 }
1127
1128 LayoutEngine& Controller::GetLayoutEngine()
1129 {
1130   return mImpl->mLayoutEngine;
1131 }
1132
1133 void Controller::RequestRelayout()
1134 {
1135   mImpl->mControlInterface.RequestTextRelayout();
1136 }
1137
1138 void Controller::KeyboardFocusGainEvent()
1139 {
1140   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1141
1142   if( mImpl->mTextInput )
1143   {
1144     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1145     mImpl->mTextInput->mEventQueue.push_back( event );
1146
1147     RequestRelayout();
1148   }
1149 }
1150
1151 void Controller::KeyboardFocusLostEvent()
1152 {
1153   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1154
1155   if( mImpl->mTextInput )
1156   {
1157     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1158     mImpl->mTextInput->mEventQueue.push_back( event );
1159
1160     RequestRelayout();
1161   }
1162 }
1163
1164 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1165 {
1166   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1167
1168   if( mImpl->mTextInput )
1169   {
1170     TextInput::Event event( TextInput::KEY_EVENT );
1171     event.p1.mInt = keyEvent.keyCode;
1172     event.p2.mString = NULL;
1173
1174     const std::string& keyString = keyEvent.keyPressed;
1175     if ( !keyString.empty() )
1176     {
1177       event.p2.mString = new char[keyString.size() + 1];
1178       std::copy(keyString.begin(), keyString.end(), event.p2.mString);
1179       event.p2.mString[keyString.size()] = '\0';
1180     }
1181
1182     mImpl->mTextInput->mEventQueue.push_back( event );
1183
1184     RequestRelayout();
1185   }
1186
1187   return false;
1188 }
1189
1190 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1191 {
1192   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1193
1194   if( mImpl->mTextInput )
1195   {
1196     TextInput::Event event( TextInput::TAP_EVENT );
1197     event.p1.mUint = tapCount;
1198     event.p2.mFloat = x;
1199     event.p3.mFloat = y;
1200     mImpl->mTextInput->mEventQueue.push_back( event );
1201
1202     RequestRelayout();
1203   }
1204 }
1205
1206 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1207 {
1208   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1209
1210   if( mImpl->mTextInput )
1211   {
1212     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1213     event.p1.mUint  = state;
1214     event.p2.mFloat = x;
1215     event.p3.mFloat = y;
1216     mImpl->mTextInput->mEventQueue.push_back( event );
1217
1218     RequestRelayout();
1219   }
1220 }
1221
1222 Controller::~Controller()
1223 {
1224   delete mImpl;
1225 }
1226
1227 Controller::Controller( ControlInterface& controlInterface )
1228 : mImpl( NULL )
1229 {
1230   mImpl = new Controller::Impl( controlInterface );
1231 }
1232
1233 } // namespace Text
1234
1235 } // namespace Toolkit
1236
1237 } // namespace Dali