Merge "Added interface for queuing input events in TextController" into new_text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / 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/public-api/text/text-controller.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/public-api/text/character-set-conversion.h>
23 #include <dali-toolkit/public-api/text/layouts/layout-engine.h>
24 #include <dali-toolkit/public-api/text/logical-model.h>
25 #include <dali-toolkit/public-api/text/multi-language-support.h>
26 #include <dali-toolkit/public-api/text/script-run.h>
27 #include <dali-toolkit/public-api/text/segmentation.h>
28 #include <dali-toolkit/public-api/text/shaper.h>
29 #include <dali-toolkit/public-api/text/text-view.h>
30 #include <dali-toolkit/public-api/text/visual-model.h>
31
32 // EXTERNAL INCLUDES
33 #include <dali/public-api/text-abstraction/font-client.h>
34 #include <limits>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Text
43 {
44
45 struct Controller::TextInput
46 {
47   // Used to queue input events until DoRelayout()
48   enum EventType
49   {
50     KEYBOARD_FOCUS_GAIN_EVENT,
51     KEYBOARD_FOCUS_LOST_EVENT,
52     TAP_EVENT,
53     GRAB_HANDLE_EVENT
54   };
55
56   union Param
57   {
58     int mInt;
59     float mFloat;
60   };
61
62   struct Event
63   {
64     Event( EventType eventType )
65     : type( eventType )
66     {
67       p1.mInt = 0;
68       p2.mInt = 0;
69     }
70
71     EventType type;
72     Param p1;
73     Param p2;
74   };
75
76   TextInput( DecoratorPtr decorator )
77   : mDecorator( decorator )
78   {
79   }
80
81   DecoratorPtr mDecorator;
82
83   std::vector<Event> mEventQueue;
84 };
85
86 struct Controller::Impl
87 {
88   Impl( ControlInterface& controlInterface )
89   : mControlInterface( controlInterface ),
90     mNewText(),
91     mOperations( NO_OPERATION ),
92     mControlSize(),
93     mTextInput( NULL )
94   {
95     mLogicalModel = LogicalModel::New();
96     mVisualModel  = VisualModel::New();
97
98     mView.SetVisualModel( mVisualModel );
99
100     mFontClient = TextAbstraction::FontClient::Get();
101   }
102
103   ~Impl()
104   {
105     delete mTextInput;
106   }
107
108   ControlInterface& mControlInterface;
109
110   std::string mNewText;
111
112   LogicalModelPtr mLogicalModel;
113   VisualModelPtr  mVisualModel;
114
115   View mView;
116
117   LayoutEngine mLayoutEngine;
118
119   TextAbstraction::FontClient mFontClient;
120
121   OperationsMask mOperations;
122
123   Size mControlSize;
124
125   // Avoid allocating everything for text input until EnableTextInput()
126   Controller::TextInput* mTextInput;
127 };
128
129 ControllerPtr Controller::New( ControlInterface& controlInterface )
130 {
131   return ControllerPtr( new Controller( controlInterface ) );
132 }
133
134 void Controller::SetText( const std::string& text )
135 {
136   // Keep until size negotiation
137   mImpl->mNewText = text;
138   mImpl->mOperations = ALL_OPERATIONS;
139
140   if( mImpl->mTextInput )
141   {
142     // Cancel previously queued events
143     mImpl->mTextInput->mEventQueue.clear();
144
145     // TODO - Hide selection decorations
146   }
147 }
148
149 void Controller::EnableTextInput( DecoratorPtr decorator )
150 {
151   if( !mImpl->mTextInput )
152   {
153     mImpl->mTextInput = new TextInput( decorator );
154   }
155 }
156
157 bool Controller::Relayout( const Vector2& size )
158 {
159   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
160   {
161     // Not worth to relayout if width or height is equal to zero.
162     return false;
163   }
164
165   bool viewUpdated = false;
166
167   if( size != mImpl->mControlSize )
168   {
169     viewUpdated = DoRelayout( size, mImpl->mOperations );
170
171     // Do not re-do any operation until something changes.
172     mImpl->mOperations = NO_OPERATION;
173
174     mImpl->mControlSize = size;
175   }
176
177   return viewUpdated;
178 }
179
180 bool Controller::DoRelayout( const Vector2& size, OperationsMask operations )
181 {
182   bool viewUpdated( false );
183
184   Vector<Character> utf32Characters;
185   Length characterCount = 0u;
186   if( CONVERT_TO_UTF32 & operations )
187   {
188     std::string& text = mImpl->mNewText;
189
190     //  Convert text into UTF-32
191     utf32Characters.Resize( text.size() );
192
193     // This is a bit horrible but std::string returns a (signed) char*
194     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
195
196     // Transform a text array encoded in utf8 into an array encoded in utf32.
197     // It returns the actual number of characters.
198     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
199     utf32Characters.Resize( characterCount );
200
201     // Sets the text into the model.
202     mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
203
204     // Discard temporary text
205     text.clear();
206   }
207
208   Vector<LineBreakInfo> lineBreakInfo;
209   if( GET_LINE_BREAKS & operations )
210   {
211     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
212     // calculate the bidirectional info for each 'paragraph'.
213     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
214     // is not shaped together).
215     lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
216
217     SetLineBreakInfo( utf32Characters,
218                       lineBreakInfo );
219
220     mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
221   }
222
223   const bool getScripts = GET_SCRIPTS & operations;
224   const bool validateFonts = VALIDATE_FONTS & operations;
225
226   Vector<ScriptRun> scripts;
227   Vector<FontRun> fonts;
228   if( getScripts || validateFonts )
229   {
230     // Validates the fonts assigned by the application or assigns default ones.
231     // It makes sure all the characters are going to be rendered by the correct font.
232     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
233
234     if( getScripts )
235     {
236       // Retrieves the scripts used in the text.
237       multilanguageSupport.SetScripts( utf32Characters,
238                                        lineBreakInfo,
239                                        scripts );
240
241       // Sets the scripts into the model.
242       mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
243     }
244
245     if( validateFonts )
246     {
247       // Validates the fonts. If there is a character with no assigned font it sets a default one.
248       // After this call, fonts are validated.
249       multilanguageSupport.ValidateFonts( utf32Characters,
250                                           scripts,
251                                           fonts );
252
253       // Sets the fonts into the model.
254       mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() );
255     }
256   }
257
258   Vector<GlyphInfo> glyphs;
259   Vector<CharacterIndex> characterIndices;
260   Vector<Length> charactersPerGlyph;
261   if( SHAPE_TEXT & operations )
262   {
263     // Shapes the text.
264     ShapeText( utf32Characters,
265                lineBreakInfo,
266                scripts,
267                fonts,
268                glyphs,
269                characterIndices,
270                charactersPerGlyph );
271   }
272
273   if( GET_GLYPH_METRICS & operations )
274   {
275     TextAbstraction::FontClient::Get().GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
276   }
277
278   if( LAYOUT & operations )
279   {
280     if( 0u == glyphs.Count() )
281     {
282       const Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
283
284       glyphs.Resize( numberOfGlyphs );
285       characterIndices.Resize( numberOfGlyphs );
286       charactersPerGlyph.Resize( numberOfGlyphs );
287
288       mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
289                                       0u,
290                                       numberOfGlyphs );
291
292       mImpl->mVisualModel->GetGlyphToCharacterMap( characterIndices.Begin(),
293                                                    0u,
294                                                    numberOfGlyphs );
295
296       mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
297                                                      0u,
298                                                      numberOfGlyphs );
299     }
300
301     // Update the visual model
302     mImpl->mLayoutEngine.UpdateVisualModel( size,
303                                             glyphs,
304                                             characterIndices,
305                                             charactersPerGlyph,
306                                             *mImpl->mVisualModel );
307
308     viewUpdated = true;
309   }
310
311   // TODO - process input events to move grab handle
312
313   return viewUpdated;
314 }
315
316 Vector3 Controller::GetNaturalSize()
317 {
318   // Operations that can be done only once until the text changes.
319   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
320                                                                          GET_SCRIPTS      |
321                                                                          VALIDATE_FONTS   |
322                                                                          GET_LINE_BREAKS  |
323                                                                          GET_WORD_BREAKS  |
324                                                                          SHAPE_TEXT       |
325                                                                          GET_GLYPH_METRICS );
326
327   // Operations that need to be done if the size or the text changes.
328   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
329                                                                       REORDER );
330
331   const float maxFloat = std::numeric_limits<float>::max();
332   DoRelayout( Vector2( maxFloat, maxFloat ),
333               static_cast<OperationsMask>( onlyOnceOperations |
334                                            sizeOperations ) );
335
336   // Do not do again the only once operations.
337   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
338
339   // Do the size related operations again.
340   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
341
342   return Vector3( mImpl->mVisualModel->GetNaturalSize() );
343 }
344
345 float Controller::GetHeightForWidth( float width )
346 {
347   // Operations that can be done only once until the text changes.
348   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
349                                                                          GET_SCRIPTS      |
350                                                                          VALIDATE_FONTS   |
351                                                                          GET_LINE_BREAKS  |
352                                                                          GET_WORD_BREAKS  |
353                                                                          SHAPE_TEXT       |
354                                                                          GET_GLYPH_METRICS );
355
356   // Operations that need to be done if the size or the text changes.
357   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
358                                                                       REORDER );
359
360   DoRelayout( Size( width, 0.f ),
361               static_cast<OperationsMask>( onlyOnceOperations |
362                                            sizeOperations ) );
363
364   // Do not do again the only once operations.
365   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
366
367   // Do the size related operations again.
368   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
369
370   return mImpl->mVisualModel->GetActualSize().height;
371 }
372
373 View& Controller::GetView()
374 {
375   return mImpl->mView;
376 }
377
378 LayoutEngine& Controller::GetLayoutEngine()
379 {
380   return mImpl->mLayoutEngine;
381 }
382
383 void Controller::RequestRelayout()
384 {
385   mImpl->mControlInterface.RequestTextRelayout();
386 }
387
388 void Controller::KeyboardFocusGainEvent()
389 {
390   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
391
392   if( mImpl->mTextInput )
393   {
394     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
395     mImpl->mTextInput->mEventQueue.push_back( event );
396
397     RequestRelayout();
398   }
399 }
400
401 void Controller::KeyboardFocusLostEvent()
402 {
403   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
404
405   if( mImpl->mTextInput )
406   {
407     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
408     mImpl->mTextInput->mEventQueue.push_back( event );
409
410     RequestRelayout();
411   }
412 }
413
414 void Controller::TapEvent( float x, float y)
415 {
416   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
417
418   if( mImpl->mTextInput )
419   {
420     TextInput::Event event( TextInput::TAP_EVENT );
421     event.p1.mFloat = x;
422     event.p2.mFloat = y;
423
424     RequestRelayout();
425   }
426 }
427
428 void Controller::GrabHandleEvent( GrabHandleState state, float x )
429 {
430   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
431
432   if( mImpl->mTextInput )
433   {
434     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
435     event.p1.mInt   = state;
436     event.p2.mFloat = x;
437
438     RequestRelayout();
439   }
440 }
441
442 Controller::~Controller()
443 {
444   delete mImpl;
445 }
446
447 Controller::Controller( ControlInterface& controlInterface )
448 : mImpl( NULL )
449 {
450   mImpl = new Controller::Impl( controlInterface );
451 }
452
453 } // namespace Text
454
455 } // namespace Toolkit
456
457 } // namespace Dali