995354c6bed93fc787aa220f2f386f5485446bfc
[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/text-abstraction/font-client.h>
37
38 using std::vector;
39
40 namespace Dali
41 {
42
43 namespace Toolkit
44 {
45
46 namespace Text
47 {
48
49 struct Controller::TextInput
50 {
51   // Used to queue input events until DoRelayout()
52   enum EventType
53   {
54     KEYBOARD_FOCUS_GAIN_EVENT,
55     KEYBOARD_FOCUS_LOST_EVENT,
56     TAP_EVENT,
57     GRAB_HANDLE_EVENT
58   };
59
60   union Param
61   {
62     int mInt;
63     unsigned int mUint;
64     float mFloat;
65   };
66
67   struct Event
68   {
69     Event( EventType eventType )
70     : type( eventType )
71     {
72       p1.mInt = 0;
73       p2.mInt = 0;
74     }
75
76     EventType type;
77     Param p1;
78     Param p2;
79     Param p3;
80   };
81
82   enum State
83   {
84     INACTIVE,
85     SELECTING,
86     EDITING
87   };
88
89   TextInput( LogicalModelPtr logicalModel,
90              VisualModelPtr visualModel,
91              DecoratorPtr decorator )
92   : mLogicalModel( logicalModel ),
93     mVisualModel( visualModel ),
94     mDecorator( decorator ),
95     mState( INACTIVE )
96   {
97   }
98
99   /**
100    * @brief Helper to move the cursor, grab handle etc.
101    */
102   bool ProcessTouchEvents()
103   {
104     mDecoratorUpdated = false;
105
106     if( mDecorator )
107     {
108       for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
109       {
110         switch( iter->type )
111         {
112           case KEYBOARD_FOCUS_GAIN_EVENT:
113           {
114             OnKeyboardFocus( true );
115             break;
116           }
117           case KEYBOARD_FOCUS_LOST_EVENT:
118           {
119             OnKeyboardFocus( false );
120             break;
121           }
122           case TAP_EVENT:
123           {
124             OnTapEvent( *iter );
125             break;
126           }
127           case GRAB_HANDLE_EVENT:
128           {
129             OnGrabHandleEvent( *iter );
130             break;
131           }
132         }
133       }
134     }
135
136     mEventQueue.clear();
137
138     return mDecoratorUpdated;
139   }
140
141   void OnKeyboardFocus( bool hasFocus )
142   {
143     // TODO
144   }
145
146   void OnTapEvent( const Event& event )
147   {
148     if( 1u == event.p1.mUint )
149     {
150       mState = TextInput::EDITING;
151       mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
152       mDecorator->StartCursorBlink();
153       mDecorator->SetGrabHandleActive( true );
154
155       float xPosition = event.p2.mFloat;
156       float yPosition = event.p3.mFloat;
157       float height(0.0f);
158       GetClosestCursorPosition( xPosition, yPosition, height );
159       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
160
161       mDecoratorUpdated = true;
162     }
163     else if( 2u == event.p1.mUint )
164     {
165       mState = TextInput::SELECTING;
166       mDecorator->SetGrabHandleActive( false );
167       mDecorator->SetSelectionActive( true );
168       mDecoratorUpdated = true;
169     }
170   }
171
172   void OnGrabHandleEvent( const Event& event )
173   {
174     unsigned int state = event.p1.mUint;
175
176     if( GRAB_HANDLE_PRESSED == state )
177     {
178       float xPosition = event.p2.mFloat;
179       float yPosition = event.p3.mFloat;
180       float height(0.0f);
181
182       GetClosestCursorPosition( xPosition, yPosition, height );
183
184       mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
185       mDecoratorUpdated = true;
186     }
187   }
188
189   void GetClosestCursorPosition( float& x, float& y, float& height )
190   {
191     // TODO - Look at LineRuns first
192
193     Text::Length numberOfGlyphs = mVisualModel->GetNumberOfGlyphs();
194     if( 0 == numberOfGlyphs )
195     {
196       return;
197     }
198
199     Vector<GlyphInfo> glyphs;
200     glyphs.Resize( numberOfGlyphs );
201     mVisualModel->GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
202
203     std::vector<Vector2> positions;
204     positions.resize( numberOfGlyphs );
205     mVisualModel->GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
206
207     unsigned int closestGlyph = 0;
208     float closestDistance = std::numeric_limits<float>::max();
209
210     for( unsigned int i=0; i<glyphs.Count(); ++i )
211     {
212       float glyphX = positions[i].x + glyphs[i].width*0.5f;
213       float glyphY = positions[i].y + glyphs[i].height*0.5f;
214
215       float distanceToGlyph = fabsf( glyphX - x ) + fabsf( glyphY - y );
216
217       if( distanceToGlyph < closestDistance )
218       {
219         closestDistance = distanceToGlyph;
220         closestGlyph = i;
221       }
222     }
223
224     // TODO - Consider RTL languages
225     x = positions[closestGlyph].x + glyphs[closestGlyph].width;
226     y = 0.0f;
227
228     FontMetrics metrics;
229     TextAbstraction::FontClient::Get().GetFontMetrics( glyphs[closestGlyph].fontId, metrics );
230     height = metrics.height; // TODO - Fix for multi-line
231   }
232
233   LogicalModelPtr mLogicalModel;
234   VisualModelPtr  mVisualModel;
235   DecoratorPtr    mDecorator;
236
237   State mState;
238
239   /**
240    * This is used to delay handling events until after the model has been updated.
241    * The number of updates to the model is minimized to improve performance.
242    */
243   vector<Event> mEventQueue; ///< The queue of touch events etc.
244
245   bool mDecoratorUpdated;
246 };
247
248 struct Controller::Impl
249 {
250   Impl( ControlInterface& controlInterface )
251   : mControlInterface( controlInterface ),
252     mNewText(),
253     mOperations( NO_OPERATION ),
254     mControlSize(),
255     mTextInput( NULL )
256   {
257     mLogicalModel = LogicalModel::New();
258     mVisualModel  = VisualModel::New();
259
260     mView.SetVisualModel( mVisualModel );
261
262     mFontClient = TextAbstraction::FontClient::Get();
263   }
264
265   ~Impl()
266   {
267     delete mTextInput;
268   }
269
270   ControlInterface& mControlInterface;
271
272   std::string mNewText;
273
274   LogicalModelPtr mLogicalModel;
275   VisualModelPtr  mVisualModel;
276
277   View mView;
278
279   LayoutEngine mLayoutEngine;
280
281   TextAbstraction::FontClient mFontClient;
282
283   OperationsMask mOperations;
284
285   Size mControlSize;
286
287   // Avoid allocating everything for text input until EnableTextInput()
288   Controller::TextInput* mTextInput;
289 };
290
291 ControllerPtr Controller::New( ControlInterface& controlInterface )
292 {
293   return ControllerPtr( new Controller( controlInterface ) );
294 }
295
296 void Controller::SetText( const std::string& text )
297 {
298   // Keep until size negotiation
299   mImpl->mNewText = text;
300   mImpl->mOperations = ALL_OPERATIONS;
301
302   if( mImpl->mTextInput )
303   {
304     // Cancel previously queued events
305     mImpl->mTextInput->mEventQueue.clear();
306
307     // TODO - Hide selection decorations
308   }
309 }
310
311 void Controller::GetText( std::string& text )
312 {
313   if( !mImpl->mNewText.empty() )
314   {
315     text = mImpl->mNewText;
316   }
317   else
318   {
319     // TODO - Convert from UTF-32
320   }
321 }
322
323 void Controller::EnableTextInput( DecoratorPtr decorator )
324 {
325   if( !mImpl->mTextInput )
326   {
327     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
328   }
329 }
330
331 bool Controller::Relayout( const Vector2& size )
332 {
333   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
334   {
335     // Not worth to relayout if width or height is equal to zero.
336     return false;
337   }
338
339   bool updated = false;
340
341   if( size != mImpl->mControlSize )
342   {
343     updated = DoRelayout( size, mImpl->mOperations );
344
345     // Do not re-do any operation until something changes.
346     mImpl->mOperations = NO_OPERATION;
347
348     mImpl->mControlSize = size;
349   }
350
351   if( mImpl->mTextInput )
352   {
353     // Move the cursor, grab handle etc.
354     updated = mImpl->mTextInput->ProcessTouchEvents() || updated;
355   }
356
357   return updated;
358 }
359
360 bool Controller::DoRelayout( const Vector2& size, OperationsMask operations )
361 {
362   bool viewUpdated( false );
363
364   Vector<Character> utf32Characters;
365   Length characterCount = 0u;
366   if( CONVERT_TO_UTF32 & operations )
367   {
368     std::string& text = mImpl->mNewText;
369
370     //  Convert text into UTF-32
371     utf32Characters.Resize( text.size() );
372
373     // This is a bit horrible but std::string returns a (signed) char*
374     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
375
376     // Transform a text array encoded in utf8 into an array encoded in utf32.
377     // It returns the actual number of characters.
378     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
379     utf32Characters.Resize( characterCount );
380
381     // Sets the text into the model.
382     mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
383
384     // Discard temporary text
385     //text.clear(); temporary keep the text. will be fixed in the next patch.
386   }
387
388   Vector<LineBreakInfo> lineBreakInfo;
389   if( GET_LINE_BREAKS & operations )
390   {
391     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
392     // calculate the bidirectional info for each 'paragraph'.
393     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
394     // is not shaped together).
395     lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
396
397     SetLineBreakInfo( utf32Characters,
398                       lineBreakInfo );
399
400     mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
401   }
402
403   Vector<WordBreakInfo> wordBreakInfo;
404   if( GET_WORD_BREAKS & operations )
405   {
406     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
407     wordBreakInfo.Resize( characterCount, TextAbstraction::WORD_NO_BREAK );
408
409     SetWordBreakInfo( utf32Characters,
410                       wordBreakInfo );
411
412     mImpl->mLogicalModel->SetWordBreakInfo( wordBreakInfo.Begin(), characterCount );
413   }
414
415   const bool getScripts = GET_SCRIPTS & operations;
416   const bool validateFonts = VALIDATE_FONTS & operations;
417
418   Vector<ScriptRun> scripts;
419   Vector<FontRun> fonts;
420   if( getScripts || validateFonts )
421   {
422     // Validates the fonts assigned by the application or assigns default ones.
423     // It makes sure all the characters are going to be rendered by the correct font.
424     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
425
426     if( getScripts )
427     {
428       // Retrieves the scripts used in the text.
429       multilanguageSupport.SetScripts( utf32Characters,
430                                        lineBreakInfo,
431                                        scripts );
432
433       // Sets the scripts into the model.
434       mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
435     }
436
437     if( validateFonts )
438     {
439       // Validates the fonts. If there is a character with no assigned font it sets a default one.
440       // After this call, fonts are validated.
441       multilanguageSupport.ValidateFonts( utf32Characters,
442                                           scripts,
443                                           fonts );
444
445       // Sets the fonts into the model.
446       mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() );
447     }
448   }
449
450   Vector<GlyphInfo> glyphs;
451   Vector<CharacterIndex> glyphsToCharactersMap;
452   Vector<Length> charactersPerGlyph;
453   if( SHAPE_TEXT & operations )
454   {
455     // Shapes the text.
456     ShapeText( utf32Characters,
457                lineBreakInfo,
458                scripts,
459                fonts,
460                glyphs,
461                glyphsToCharactersMap,
462                charactersPerGlyph );
463   }
464
465   if( GET_GLYPH_METRICS & operations )
466   {
467     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
468   }
469
470   Length numberOfGlyphs = glyphs.Count();
471   if( 0u != numberOfGlyphs )
472   {
473     // Sets the glyphs into the model.
474     mImpl->mVisualModel->SetGlyphs( glyphs.Begin(),
475                                     glyphsToCharactersMap.Begin(),
476                                     charactersPerGlyph.Begin(),
477                                     numberOfGlyphs );
478   }
479
480   if( LAYOUT & operations )
481   {
482     if( 0u == numberOfGlyphs )
483     {
484       const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
485       numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
486
487       lineBreakInfo.Resize( numberOfCharacters );
488       wordBreakInfo.Resize( numberOfCharacters );
489       glyphs.Resize( numberOfGlyphs );
490       glyphsToCharactersMap.Resize( numberOfGlyphs );
491       charactersPerGlyph.Resize( numberOfGlyphs );
492
493       mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
494                                               0u,
495                                               numberOfCharacters );
496
497       mImpl->mLogicalModel->GetWordBreakInfo( wordBreakInfo.Begin(),
498                                               0u,
499                                               numberOfCharacters );
500
501       mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
502                                       0u,
503                                       numberOfGlyphs );
504
505       mImpl->mVisualModel->GetGlyphToCharacterMap( glyphsToCharactersMap.Begin(),
506                                                    0u,
507                                                    numberOfGlyphs );
508
509       mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
510                                                      0u,
511                                                      numberOfGlyphs );
512     }
513
514     // Set the layout parameters.
515     LayoutParameters layoutParameters( size,
516                                        lineBreakInfo.Begin(),
517                                        wordBreakInfo.Begin(),
518                                        numberOfGlyphs,
519                                        glyphs.Begin(),
520                                        glyphsToCharactersMap.Begin(),
521                                        charactersPerGlyph.Begin() );
522
523     // Reserve space to set the positions of the glyphs.
524     Vector<Vector2> glyphPositions;
525     glyphPositions.Resize( numberOfGlyphs );
526
527     Size layoutSize;
528
529     // Update the visual model
530     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
531                                                    glyphPositions,
532                                                    layoutSize );
533
534     // Sets the positions into the model.
535     mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(),
536                                             numberOfGlyphs );
537
538     // Sets the actual size.
539     mImpl->mVisualModel->SetActualSize( layoutSize );
540   }
541
542   return viewUpdated;
543 }
544
545 Vector3 Controller::GetNaturalSize()
546 {
547   // TODO - Finish implementing
548   return Vector3::ZERO;
549
550   // Operations that can be done only once until the text changes.
551   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
552                                                                          GET_SCRIPTS      |
553                                                                          VALIDATE_FONTS   |
554                                                                          GET_LINE_BREAKS  |
555                                                                          GET_WORD_BREAKS  |
556                                                                          SHAPE_TEXT       |
557                                                                          GET_GLYPH_METRICS );
558
559   // Operations that need to be done if the size or the text changes.
560   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
561                                                                       REORDER );
562
563   const float maxFloat = std::numeric_limits<float>::max();
564   DoRelayout( Vector2( maxFloat, maxFloat ),
565               static_cast<OperationsMask>( onlyOnceOperations |
566                                            sizeOperations ) );
567
568   // Do not do again the only once operations.
569   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
570
571   // Do the size related operations again.
572   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
573
574   return Vector3( mImpl->mVisualModel->GetNaturalSize() );
575 }
576
577 float Controller::GetHeightForWidth( float width )
578 {
579   // Operations that can be done only once until the text changes.
580   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
581                                                                          GET_SCRIPTS      |
582                                                                          VALIDATE_FONTS   |
583                                                                          GET_LINE_BREAKS  |
584                                                                          GET_WORD_BREAKS  |
585                                                                          SHAPE_TEXT       |
586                                                                          GET_GLYPH_METRICS );
587
588   // Operations that need to be done if the size or the text changes.
589   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
590                                                                       REORDER );
591
592   DoRelayout( Size( width, 0.f ),
593               static_cast<OperationsMask>( onlyOnceOperations |
594                                            sizeOperations ) );
595
596   // Do not do again the only once operations.
597   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
598
599   // Do the size related operations again.
600   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
601
602   return mImpl->mVisualModel->GetActualSize().height;
603 }
604
605 View& Controller::GetView()
606 {
607   return mImpl->mView;
608 }
609
610 LayoutEngine& Controller::GetLayoutEngine()
611 {
612   return mImpl->mLayoutEngine;
613 }
614
615 void Controller::RequestRelayout()
616 {
617   mImpl->mControlInterface.RequestTextRelayout();
618 }
619
620 void Controller::KeyboardFocusGainEvent()
621 {
622   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
623
624   if( mImpl->mTextInput )
625   {
626     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
627     mImpl->mTextInput->mEventQueue.push_back( event );
628
629     RequestRelayout();
630   }
631 }
632
633 void Controller::KeyboardFocusLostEvent()
634 {
635   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
636
637   if( mImpl->mTextInput )
638   {
639     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
640     mImpl->mTextInput->mEventQueue.push_back( event );
641
642     RequestRelayout();
643   }
644 }
645
646 void Controller::TapEvent( unsigned int tapCount, float x, float y )
647 {
648   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
649
650   if( mImpl->mTextInput )
651   {
652     TextInput::Event event( TextInput::TAP_EVENT );
653     event.p1.mUint = tapCount;
654     event.p2.mFloat = x;
655     event.p3.mFloat = y;
656     mImpl->mTextInput->mEventQueue.push_back( event );
657
658     RequestRelayout();
659   }
660 }
661
662 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
663 {
664   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
665
666   if( mImpl->mTextInput )
667   {
668     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
669     event.p1.mUint  = state;
670     event.p2.mFloat = x;
671     event.p3.mFloat = y;
672     mImpl->mTextInput->mEventQueue.push_back( event );
673
674     RequestRelayout();
675   }
676 }
677
678 Controller::~Controller()
679 {
680   delete mImpl;
681 }
682
683 Controller::Controller( ControlInterface& controlInterface )
684 : mImpl( NULL )
685 {
686   mImpl = new Controller::Impl( controlInterface );
687 }
688
689 } // namespace Text
690
691 } // namespace Toolkit
692
693 } // namespace Dali