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