07cb7fe859cf8d98360f8abb2a4755b38d91ff0d
[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 <dali/public-api/adaptor-framework/key.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/devel-api/adaptor-framework/clipboard-event-notifier.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-parameters.h>
31 #include <dali-toolkit/internal/text/text-controller-impl.h>
32
33 namespace
34 {
35
36 #if defined(DEBUG_ENABLED)
37   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
38 #endif
39
40 const float MAX_FLOAT = std::numeric_limits<float>::max();
41 const unsigned int POINTS_PER_INCH = 72;
42
43 const std::string EMPTY_STRING("");
44 const unsigned int ZERO = 0u;
45
46 float ConvertToEven( float value )
47 {
48   int intValue(static_cast<int>( value ));
49   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
50 }
51
52 } // namespace
53
54 namespace Dali
55 {
56
57 namespace Toolkit
58 {
59
60 namespace Text
61 {
62
63 ControllerPtr Controller::New( ControlInterface& controlInterface )
64 {
65   return ControllerPtr( new Controller( controlInterface ) );
66 }
67
68 void Controller::EnableTextInput( DecoratorPtr decorator )
69 {
70   if( !mImpl->mEventData )
71   {
72     mImpl->mEventData = new EventData( decorator );
73   }
74 }
75
76 void Controller::SetText( const std::string& text )
77 {
78   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
79
80   // Reset keyboard as text changed
81   mImpl->ResetImfManager();
82
83   // Remove the previously set text
84   ResetText();
85
86   CharacterIndex lastCursorIndex = 0u;
87
88   if( mImpl->mEventData )
89   {
90     // If popup shown then hide it by switching to Editing state
91     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
92         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
93         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
94     {
95       mImpl->ChangeState( EventData::EDITING );
96     }
97   }
98
99   if( !text.empty() )
100   {
101     //  Convert text into UTF-32
102     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
103     utf32Characters.Resize( text.size() );
104
105     // This is a bit horrible but std::string returns a (signed) char*
106     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
107
108     // Transform a text array encoded in utf8 into an array encoded in utf32.
109     // It returns the actual number of characters.
110     Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
111     utf32Characters.Resize( characterCount );
112
113     DALI_ASSERT_DEBUG( text.size() >= characterCount && "Invalid UTF32 conversion length" );
114     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, text.size(), mImpl->mLogicalModel->mText.Count() );
115
116     // To reset the cursor position
117     lastCursorIndex = characterCount;
118
119     // Update the rest of the model during size negotiation
120     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
121
122     // The natural size needs to be re-calculated.
123     mImpl->mRecalculateNaturalSize = true;
124
125     // Apply modifications to the model
126     mImpl->mOperationsPending = ALL_OPERATIONS;
127   }
128   else
129   {
130     ShowPlaceholderText();
131   }
132
133   // Resets the cursor position.
134   ResetCursorPosition( lastCursorIndex );
135
136   // Scrolls the text to make the cursor visible.
137   ResetScrollPosition();
138
139   mImpl->RequestRelayout();
140
141   if( mImpl->mEventData )
142   {
143     // Cancel previously queued events
144     mImpl->mEventData->mEventQueue.clear();
145   }
146
147   // Notify IMF as text changed
148   NotifyImfManager();
149
150   // Do this last since it provides callbacks into application code
151   mImpl->mControlInterface.TextChanged();
152 }
153
154 void Controller::GetText( std::string& text ) const
155 {
156   if( ! mImpl->IsShowingPlaceholderText() )
157   {
158     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
159
160     if( 0u != utf32Characters.Count() )
161     {
162       Utf32ToUtf8( &utf32Characters[0], utf32Characters.Count(), text );
163     }
164   }
165   else
166   {
167     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
168   }
169 }
170
171 unsigned int Controller::GetLogicalCursorPosition() const
172 {
173   if( mImpl->mEventData )
174   {
175     return mImpl->mEventData->mPrimaryCursorPosition;
176   }
177
178   return 0u;
179 }
180
181 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
182 {
183   if( mImpl->mEventData )
184   {
185     if( PLACEHOLDER_TYPE_INACTIVE == type )
186     {
187       mImpl->mEventData->mPlaceholderTextInactive = text;
188     }
189     else
190     {
191       mImpl->mEventData->mPlaceholderTextActive = text;
192     }
193
194     // Update placeholder if there is no text
195     if( mImpl->IsShowingPlaceholderText() ||
196         0u == mImpl->mLogicalModel->mText.Count() )
197     {
198       ShowPlaceholderText();
199     }
200   }
201 }
202
203 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
204 {
205   if( mImpl->mEventData )
206   {
207     if( PLACEHOLDER_TYPE_INACTIVE == type )
208     {
209       text = mImpl->mEventData->mPlaceholderTextInactive;
210     }
211     else
212     {
213       text = mImpl->mEventData->mPlaceholderTextActive;
214     }
215   }
216 }
217
218 void Controller::SetMaximumNumberOfCharacters( int maxCharacters )
219 {
220   if ( maxCharacters >= 0 )
221   {
222     mImpl->mMaximumNumberOfCharacters = maxCharacters;
223   }
224 }
225
226 int Controller::GetMaximumNumberOfCharacters()
227 {
228   return mImpl->mMaximumNumberOfCharacters;
229 }
230
231 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
232 {
233   if( !mImpl->mFontDefaults )
234   {
235     mImpl->mFontDefaults = new FontDefaults();
236   }
237
238   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
239   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
240   mImpl->mUserDefinedFontFamily = true;
241
242   // Clear the font-specific data
243   ClearFontData();
244
245   mImpl->mOperationsPending = ALL_OPERATIONS;
246   mImpl->mRecalculateNaturalSize = true;
247
248   mImpl->RequestRelayout();
249 }
250
251 const std::string& Controller::GetDefaultFontFamily() const
252 {
253   if( mImpl->mFontDefaults )
254   {
255     return mImpl->mFontDefaults->mFontDescription.family;
256   }
257
258   return EMPTY_STRING;
259 }
260
261 void Controller::SetDefaultFontStyle( const std::string& style )
262 {
263   if( !mImpl->mFontDefaults )
264   {
265     mImpl->mFontDefaults = new FontDefaults();
266   }
267
268   mImpl->mFontDefaults->mFontStyle = style;
269 }
270
271 const std::string& Controller::GetDefaultFontStyle() const
272 {
273   if( mImpl->mFontDefaults )
274   {
275     return mImpl->mFontDefaults->mFontStyle;
276   }
277
278   return EMPTY_STRING;
279 }
280
281 void Controller::SetDefaultFontWidth( FontWidth width )
282 {
283   if( !mImpl->mFontDefaults )
284   {
285     mImpl->mFontDefaults = new FontDefaults();
286   }
287
288   mImpl->mFontDefaults->mFontDescription.width = width;
289
290   // Clear the font-specific data
291   ClearFontData();
292
293   mImpl->mOperationsPending = ALL_OPERATIONS;
294   mImpl->mRecalculateNaturalSize = true;
295
296   mImpl->RequestRelayout();
297 }
298
299 FontWidth Controller::GetDefaultFontWidth() const
300 {
301   if( mImpl->mFontDefaults )
302   {
303     return mImpl->mFontDefaults->mFontDescription.width;
304   }
305
306   return TextAbstraction::FontWidth::NORMAL;
307 }
308
309 void Controller::SetDefaultFontWeight( FontWeight weight )
310 {
311   if( !mImpl->mFontDefaults )
312   {
313     mImpl->mFontDefaults = new FontDefaults();
314   }
315
316   mImpl->mFontDefaults->mFontDescription.weight = weight;
317
318   // Clear the font-specific data
319   ClearFontData();
320
321   mImpl->mOperationsPending = ALL_OPERATIONS;
322   mImpl->mRecalculateNaturalSize = true;
323
324   mImpl->RequestRelayout();
325 }
326
327 FontWeight Controller::GetDefaultFontWeight() const
328 {
329   if( mImpl->mFontDefaults )
330   {
331     return mImpl->mFontDefaults->mFontDescription.weight;
332   }
333
334   return TextAbstraction::FontWeight::NORMAL;
335 }
336
337 void Controller::SetDefaultFontSlant( FontSlant slant )
338 {
339   if( !mImpl->mFontDefaults )
340   {
341     mImpl->mFontDefaults = new FontDefaults();
342   }
343
344   mImpl->mFontDefaults->mFontDescription.slant = slant;
345
346   // Clear the font-specific data
347   ClearFontData();
348
349   mImpl->mOperationsPending = ALL_OPERATIONS;
350   mImpl->mRecalculateNaturalSize = true;
351
352   mImpl->RequestRelayout();
353 }
354
355 FontSlant Controller::GetDefaultFontSlant() const
356 {
357   if( mImpl->mFontDefaults )
358   {
359     return mImpl->mFontDefaults->mFontDescription.slant;
360   }
361
362   return TextAbstraction::FontSlant::NORMAL;
363 }
364
365 void Controller::SetDefaultPointSize( float pointSize )
366 {
367   if( !mImpl->mFontDefaults )
368   {
369     mImpl->mFontDefaults = new FontDefaults();
370   }
371
372   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
373
374   unsigned int horizontalDpi( 0u );
375   unsigned int verticalDpi( 0u );
376   mImpl->mFontClient.GetDpi( horizontalDpi, verticalDpi );
377
378   // Adjust the metrics if the fixed-size font should be down-scaled
379   int maxEmojiSize( pointSize/POINTS_PER_INCH * verticalDpi );
380   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultPointSize %p setting MaxEmojiSize %d\n", this, maxEmojiSize );
381   mImpl->mMetrics->SetMaxEmojiSize( maxEmojiSize );
382
383   // Clear the font-specific data
384   ClearFontData();
385
386   mImpl->mOperationsPending = ALL_OPERATIONS;
387   mImpl->mRecalculateNaturalSize = true;
388
389   mImpl->RequestRelayout();
390 }
391
392 float Controller::GetDefaultPointSize() const
393 {
394   if( mImpl->mFontDefaults )
395   {
396     return mImpl->mFontDefaults->mDefaultPointSize;
397   }
398
399   return 0.0f;
400 }
401
402 void Controller::UpdateAfterFontChange( std::string& newDefaultFont )
403 {
404   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange");
405
406   if ( !mImpl->mUserDefinedFontFamily ) // If user defined font then should not update when system font changes
407   {
408     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
409     ClearFontData();
410     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
411     mImpl->UpdateModel( ALL_OPERATIONS );
412     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
413     mImpl->mRecalculateNaturalSize = true;
414     mImpl->RequestRelayout();
415   }
416 }
417
418 void Controller::SetTextColor( const Vector4& textColor )
419 {
420   mImpl->mTextColor = textColor;
421
422   if( !mImpl->IsShowingPlaceholderText() )
423   {
424     mImpl->mVisualModel->SetTextColor( textColor );
425
426     mImpl->RequestRelayout();
427   }
428 }
429
430 const Vector4& Controller::GetTextColor() const
431 {
432   return mImpl->mTextColor;
433 }
434
435 bool Controller::RemoveText( int cursorOffset, int numberOfChars )
436 {
437   bool removed( false );
438
439   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfChars %d\n",
440                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfChars );
441
442   if( !mImpl->IsShowingPlaceholderText() )
443   {
444     // Delete at current cursor position
445     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
446     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
447
448     CharacterIndex cursorIndex = oldCursorIndex;
449
450     // Validate the cursor position & number of characters
451     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
452     {
453       cursorIndex = oldCursorIndex + cursorOffset;
454     }
455
456     if( (cursorIndex + numberOfChars) > currentText.Count() )
457     {
458       numberOfChars = currentText.Count() - cursorIndex;
459     }
460
461     if( (cursorIndex + numberOfChars) <= currentText.Count() )
462     {
463       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
464       Vector<Character>::Iterator last  = first + numberOfChars;
465
466       currentText.Erase( first, last );
467
468       // Cursor position retreat
469       oldCursorIndex = cursorIndex;
470
471       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfChars );
472       removed = true;
473     }
474   }
475
476   return removed;
477 }
478
479 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
480 {
481   if( mImpl->mEventData )
482   {
483     mImpl->mEventData->mPlaceholderTextColor = textColor;
484   }
485
486   if( mImpl->IsShowingPlaceholderText() )
487   {
488     mImpl->mVisualModel->SetTextColor( textColor );
489     mImpl->RequestRelayout();
490   }
491 }
492
493 const Vector4& Controller::GetPlaceholderTextColor() const
494 {
495   if( mImpl->mEventData )
496   {
497     return mImpl->mEventData->mPlaceholderTextColor;
498   }
499
500   return Color::BLACK;
501 }
502
503 void Controller::SetShadowOffset( const Vector2& shadowOffset )
504 {
505   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
506
507   mImpl->RequestRelayout();
508 }
509
510 const Vector2& Controller::GetShadowOffset() const
511 {
512   return mImpl->mVisualModel->GetShadowOffset();
513 }
514
515 void Controller::SetShadowColor( const Vector4& shadowColor )
516 {
517   mImpl->mVisualModel->SetShadowColor( shadowColor );
518
519   mImpl->RequestRelayout();
520 }
521
522 const Vector4& Controller::GetShadowColor() const
523 {
524   return mImpl->mVisualModel->GetShadowColor();
525 }
526
527 void Controller::SetUnderlineColor( const Vector4& color )
528 {
529   mImpl->mVisualModel->SetUnderlineColor( color );
530
531   mImpl->RequestRelayout();
532 }
533
534 const Vector4& Controller::GetUnderlineColor() const
535 {
536   return mImpl->mVisualModel->GetUnderlineColor();
537 }
538
539 void Controller::SetUnderlineEnabled( bool enabled )
540 {
541   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
542
543   mImpl->RequestRelayout();
544 }
545
546 bool Controller::IsUnderlineEnabled() const
547 {
548   return mImpl->mVisualModel->IsUnderlineEnabled();
549 }
550
551 void Controller::SetUnderlineHeight( float height )
552 {
553   mImpl->mVisualModel->SetUnderlineHeight( height );
554
555   mImpl->RequestRelayout();
556 }
557
558 float Controller::GetUnderlineHeight() const
559 {
560   return mImpl->mVisualModel->GetUnderlineHeight();
561 }
562
563 void Controller::SetEnableCursorBlink( bool enable )
564 {
565   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
566
567   if( mImpl->mEventData )
568   {
569     mImpl->mEventData->mCursorBlinkEnabled = enable;
570
571     if( !enable &&
572         mImpl->mEventData->mDecorator )
573     {
574       mImpl->mEventData->mDecorator->StopCursorBlink();
575     }
576   }
577 }
578
579 bool Controller::GetEnableCursorBlink() const
580 {
581   if( mImpl->mEventData )
582   {
583     return mImpl->mEventData->mCursorBlinkEnabled;
584   }
585
586   return false;
587 }
588
589 const Vector2& Controller::GetScrollPosition() const
590 {
591   if( mImpl->mEventData )
592   {
593     return mImpl->mEventData->mScrollPosition;
594   }
595
596   return Vector2::ZERO;
597 }
598
599 const Vector2& Controller::GetAlignmentOffset() const
600 {
601   return mImpl->mAlignmentOffset;
602 }
603
604 Vector3 Controller::GetNaturalSize()
605 {
606   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
607   Vector3 naturalSize;
608
609   // Make sure the model is up-to-date before layouting
610   ProcessModifyEvents();
611
612   if( mImpl->mRecalculateNaturalSize )
613   {
614     // Operations that can be done only once until the text changes.
615     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
616                                                                            GET_SCRIPTS       |
617                                                                            VALIDATE_FONTS    |
618                                                                            GET_LINE_BREAKS   |
619                                                                            GET_WORD_BREAKS   |
620                                                                            BIDI_INFO         |
621                                                                            SHAPE_TEXT        |
622                                                                            GET_GLYPH_METRICS );
623     // Make sure the model is up-to-date before layouting
624     mImpl->UpdateModel( onlyOnceOperations );
625
626     // Operations that need to be done if the size changes.
627     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
628                                                                         ALIGN  |
629                                                                         REORDER );
630
631     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
632                 static_cast<OperationsMask>( onlyOnceOperations |
633                                              sizeOperations ),
634                 naturalSize.GetVectorXY() );
635
636     // Do not do again the only once operations.
637     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
638
639     // Do the size related operations again.
640     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
641
642     // Stores the natural size to avoid recalculate it again
643     // unless the text/style changes.
644     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
645
646     mImpl->mRecalculateNaturalSize = false;
647
648     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
649   }
650   else
651   {
652     naturalSize = mImpl->mVisualModel->GetNaturalSize();
653
654     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
655   }
656
657   naturalSize.x = ConvertToEven( naturalSize.x );
658   naturalSize.y = ConvertToEven( naturalSize.y );
659
660   return naturalSize;
661 }
662
663 float Controller::GetHeightForWidth( float width )
664 {
665   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
666   // Make sure the model is up-to-date before layouting
667   ProcessModifyEvents();
668
669   Size layoutSize;
670   if( width != mImpl->mVisualModel->mControlSize.width )
671   {
672     // Operations that can be done only once until the text changes.
673     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
674                                                                            GET_SCRIPTS       |
675                                                                            VALIDATE_FONTS    |
676                                                                            GET_LINE_BREAKS   |
677                                                                            GET_WORD_BREAKS   |
678                                                                            BIDI_INFO         |
679                                                                            SHAPE_TEXT        |
680                                                                            GET_GLYPH_METRICS );
681     // Make sure the model is up-to-date before layouting
682     mImpl->UpdateModel( onlyOnceOperations );
683
684     // Operations that need to be done if the size changes.
685     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
686                                                                         ALIGN  |
687                                                                         REORDER );
688
689     DoRelayout( Size( width, MAX_FLOAT ),
690                 static_cast<OperationsMask>( onlyOnceOperations |
691                                              sizeOperations ),
692                 layoutSize );
693
694     // Do not do again the only once operations.
695     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
696
697     // Do the size related operations again.
698     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
699     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
700   }
701   else
702   {
703     layoutSize = mImpl->mVisualModel->GetActualSize();
704     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
705   }
706
707   return layoutSize.height;
708 }
709
710 bool Controller::Relayout( const Size& size )
711 {
712   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f\n", this, size.width, size.height );
713
714   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
715   {
716     bool glyphsRemoved( false );
717     if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
718     {
719       mImpl->mVisualModel->mGlyphPositions.Clear();
720       glyphsRemoved = true;
721     }
722     // Not worth to relayout if width or height is equal to zero.
723     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
724     return glyphsRemoved;
725   }
726
727   const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
728
729   if( newSize )
730   {
731     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
732
733     // Operations that need to be done if the size changes.
734     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
735                                                              LAYOUT                    |
736                                                              ALIGN                     |
737                                                              UPDATE_ACTUAL_SIZE        |
738                                                              REORDER );
739
740     mImpl->mVisualModel->mControlSize = size;
741   }
742
743   // Make sure the model is up-to-date before layouting
744   ProcessModifyEvents();
745   mImpl->UpdateModel( mImpl->mOperationsPending );
746
747   Size layoutSize;
748   bool updated = DoRelayout( mImpl->mVisualModel->mControlSize,
749                              mImpl->mOperationsPending,
750                              layoutSize );
751
752   // Do not re-do any operation until something changes.
753   mImpl->mOperationsPending = NO_OPERATION;
754
755   // Keep the current offset and alignment as it will be used to update the decorator's positions (if the size changes).
756   Vector2 offset;
757   if( newSize && mImpl->mEventData )
758   {
759     offset = mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition;
760   }
761
762   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
763   CalculateTextAlignment( size );
764
765   if( mImpl->mEventData )
766   {
767     if( newSize )
768     {
769       // If there is a new size, the scroll position needs to be clamped.
770       mImpl->ClampHorizontalScroll( layoutSize );
771
772       // Update the decorator's positions is needed if there is a new size.
773       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
774     }
775
776     // Move the cursor, grab handle etc.
777     updated = mImpl->ProcessInputEvents() || updated;
778   }
779
780   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
781   return updated;
782 }
783
784 void Controller::ProcessModifyEvents()
785 {
786   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
787
788   for( unsigned int i=0; i<events.size(); ++i )
789   {
790     if( ModifyEvent::TEXT_REPLACED == events[i].type )
791     {
792       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
793       DALI_ASSERT_DEBUG( 0 == i && "Unexpected TEXT_REPLACED event" );
794
795       TextReplacedEvent();
796     }
797     else if( ModifyEvent::TEXT_INSERTED == events[i].type )
798     {
799       TextInsertedEvent();
800     }
801     else if( ModifyEvent::TEXT_DELETED == events[i].type )
802     {
803       // Placeholder-text cannot be deleted
804       if( !mImpl->IsShowingPlaceholderText() )
805       {
806         TextDeletedEvent();
807       }
808     }
809   }
810
811   if( mImpl->mEventData &&
812       0 != events.size() )
813   {
814     // When the text is being modified, delay cursor blinking
815     mImpl->mEventData->mDecorator->DelayCursorBlink();
816   }
817
818   // Discard temporary text
819   events.clear();
820 }
821
822 void Controller::ResetText()
823 {
824   // Reset buffers.
825   mImpl->mLogicalModel->mText.Clear();
826   ClearModelData();
827
828   // We have cleared everything including the placeholder-text
829   mImpl->PlaceholderCleared();
830
831   // The natural size needs to be re-calculated.
832   mImpl->mRecalculateNaturalSize = true;
833
834   // Apply modifications to the model
835   mImpl->mOperationsPending = ALL_OPERATIONS;
836 }
837
838 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
839 {
840   // Reset the cursor position
841   if( NULL != mImpl->mEventData )
842   {
843     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
844
845     // Update the cursor if it's in editing mode.
846     if( ( EventData::EDITING == mImpl->mEventData->mState )            ||
847         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
848         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
849     {
850       mImpl->mEventData->mUpdateCursorPosition = true;
851     }
852   }
853 }
854
855 void Controller::ResetScrollPosition()
856 {
857   if( NULL != mImpl->mEventData )
858   {
859     // Reset the scroll position.
860     mImpl->mEventData->mScrollPosition = Vector2::ZERO;
861     mImpl->mEventData->mScrollAfterUpdatePosition = true;
862   }
863 }
864
865 void Controller::TextReplacedEvent()
866 {
867   // Reset buffers.
868   ClearModelData();
869
870   // The natural size needs to be re-calculated.
871   mImpl->mRecalculateNaturalSize = true;
872
873   // Apply modifications to the model
874   mImpl->mOperationsPending = ALL_OPERATIONS;
875   mImpl->UpdateModel( ALL_OPERATIONS );
876   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
877                                                            ALIGN              |
878                                                            UPDATE_ACTUAL_SIZE |
879                                                            REORDER );
880 }
881
882 void Controller::TextInsertedEvent()
883 {
884   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
885
886   // TODO - Optimize this
887   ClearModelData();
888
889   // The natural size needs to be re-calculated.
890   mImpl->mRecalculateNaturalSize = true;
891
892   // Apply modifications to the model; TODO - Optimize this
893   mImpl->mOperationsPending = ALL_OPERATIONS;
894   mImpl->UpdateModel( ALL_OPERATIONS );
895   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
896                                                            ALIGN              |
897                                                            UPDATE_ACTUAL_SIZE |
898                                                            REORDER );
899
900   // Queue a cursor reposition event; this must wait until after DoRelayout()
901   if( ( EventData::EDITING == mImpl->mEventData->mState )            ||
902       ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
903       ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
904   {
905     mImpl->mEventData->mUpdateCursorPosition = true;
906     mImpl->mEventData->mScrollAfterUpdatePosition = true;
907   }
908 }
909
910 void Controller::TextDeletedEvent()
911 {
912   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
913
914   // TODO - Optimize this
915   ClearModelData();
916
917   // The natural size needs to be re-calculated.
918   mImpl->mRecalculateNaturalSize = true;
919
920   // Apply modifications to the model; TODO - Optimize this
921   mImpl->mOperationsPending = ALL_OPERATIONS;
922   mImpl->UpdateModel( ALL_OPERATIONS );
923   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
924                                                            ALIGN              |
925                                                            UPDATE_ACTUAL_SIZE |
926                                                            REORDER );
927
928   // Queue a cursor reposition event; this must wait until after DoRelayout()
929   mImpl->mEventData->mUpdateCursorPosition = true;
930   if( 0u != mImpl->mLogicalModel->mText.Count() )
931   {
932     mImpl->mEventData->mScrollAfterDelete = true;
933   }
934 }
935
936 bool Controller::DoRelayout( const Size& size,
937                              OperationsMask operationsRequired,
938                              Size& layoutSize )
939 {
940   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
941   bool viewUpdated( false );
942
943   // Calculate the operations to be done.
944   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
945
946   if( LAYOUT & operations )
947   {
948     // Some vectors with data needed to layout and reorder may be void
949     // after the first time the text has been laid out.
950     // Fill the vectors again.
951
952     const Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
953
954     if( 0u == numberOfGlyphs )
955     {
956       // Nothing else to do if there is no glyphs.
957       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
958       return true;
959     }
960
961     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
962     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
963     const Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
964     const Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
965     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
966     const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
967     const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
968
969     // Set the layout parameters.
970     LayoutParameters layoutParameters( size,
971                                        textBuffer,
972                                        lineBreakInfo.Begin(),
973                                        wordBreakInfo.Begin(),
974                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
975                                        numberOfGlyphs,
976                                        glyphs.Begin(),
977                                        glyphsToCharactersMap.Begin(),
978                                        charactersPerGlyph.Begin() );
979
980     // The laid-out lines.
981     // It's not possible to know in how many lines the text is going to be laid-out,
982     // but it can be resized at least with the number of 'paragraphs' to avoid
983     // some re-allocations.
984     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
985
986     // Delete any previous laid out lines before setting the new ones.
987     lines.Clear();
988
989     // The capacity of the bidirectional paragraph info is the number of paragraphs.
990     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
991
992     // Resize the vector of positions to have the same size than the vector of glyphs.
993     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
994     glyphPositions.Resize( numberOfGlyphs );
995
996     // Whether the last character is a new paragraph character.
997     layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
998
999     // Update the visual model.
1000     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1001                                                    glyphPositions,
1002                                                    lines,
1003                                                    layoutSize );
1004
1005     if( viewUpdated )
1006     {
1007       // Reorder the lines
1008       if( REORDER & operations )
1009       {
1010         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1011
1012         // Check first if there are paragraphs with bidirectional info.
1013         if( 0u != bidirectionalInfo.Count() )
1014         {
1015           // Get the lines
1016           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
1017
1018           // Reorder the lines.
1019           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1020           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1021           ReorderLines( bidirectionalInfo,
1022                         lines,
1023                         lineBidirectionalInfoRuns );
1024
1025           // Set the bidirectional info into the model.
1026           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1027           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1028                                                        numberOfBidirectionalInfoRuns );
1029
1030           // Set the bidirectional info per line into the layout parameters.
1031           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1032           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1033
1034           // Get the character to glyph conversion table and set into the layout.
1035           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1036
1037           // Get the glyphs per character table and set into the layout.
1038           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1039
1040           // Re-layout the text. Reorder those lines with right to left characters.
1041           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1042                                                          glyphPositions );
1043
1044           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1045           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1046                  endIt = lineBidirectionalInfoRuns.End();
1047                it != endIt;
1048                ++it )
1049           {
1050             BidirectionalLineInfoRun& bidiLineInfo = *it;
1051
1052             free( bidiLineInfo.visualToLogicalMap );
1053           }
1054         }
1055       } // REORDER
1056
1057       // Sets the actual size.
1058       if( UPDATE_ACTUAL_SIZE & operations )
1059       {
1060         mImpl->mVisualModel->SetActualSize( layoutSize );
1061       }
1062     } // view updated
1063   }
1064   else
1065   {
1066     layoutSize = mImpl->mVisualModel->GetActualSize();
1067   }
1068
1069   if( ALIGN & operations )
1070   {
1071     // The laid-out lines.
1072     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1073
1074     mImpl->mLayoutEngine.Align( layoutSize,
1075                                 lines );
1076
1077     viewUpdated = true;
1078   }
1079
1080   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
1081   return viewUpdated;
1082 }
1083
1084 void Controller::SetMultiLineEnabled( bool enable )
1085 {
1086   const LayoutEngine::Layout layout = enable ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
1087
1088   if( layout != mImpl->mLayoutEngine.GetLayout() )
1089   {
1090     // Set the layout type.
1091     mImpl->mLayoutEngine.SetLayout( layout );
1092
1093     // Set the flags to redo the layout operations
1094     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
1095                                                                           UPDATE_ACTUAL_SIZE |
1096                                                                           ALIGN              |
1097                                                                           REORDER );
1098
1099     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
1100
1101     mImpl->RequestRelayout();
1102   }
1103 }
1104
1105 bool Controller::IsMultiLineEnabled() const
1106 {
1107   return LayoutEngine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
1108 }
1109
1110 void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment alignment )
1111 {
1112   if( alignment != mImpl->mLayoutEngine.GetHorizontalAlignment() )
1113   {
1114     // Set the alignment.
1115     mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
1116
1117     // Set the flag to redo the alignment operation.
1118     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1119
1120     mImpl->RequestRelayout();
1121   }
1122 }
1123
1124 LayoutEngine::HorizontalAlignment Controller::GetHorizontalAlignment() const
1125 {
1126   return mImpl->mLayoutEngine.GetHorizontalAlignment();
1127 }
1128
1129 void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment )
1130 {
1131   if( alignment != mImpl->mLayoutEngine.GetVerticalAlignment() )
1132   {
1133     // Set the alignment.
1134     mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
1135
1136     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1137
1138     mImpl->RequestRelayout();
1139   }
1140 }
1141
1142 LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
1143 {
1144   return mImpl->mLayoutEngine.GetVerticalAlignment();
1145 }
1146
1147 void Controller::CalculateTextAlignment( const Size& size )
1148 {
1149   // Get the direction of the first character.
1150   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
1151
1152   Size actualSize = mImpl->mVisualModel->GetActualSize();
1153   if( fabsf( actualSize.height ) < Math::MACHINE_EPSILON_1000 )
1154   {
1155     // Get the line height of the default font.
1156     actualSize.height = mImpl->GetDefaultFontLineHeight();
1157   }
1158
1159   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
1160   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
1161   if( firstParagraphDirection &&
1162       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
1163   {
1164     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
1165     {
1166       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
1167     }
1168     else
1169     {
1170       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
1171     }
1172   }
1173
1174   switch( horizontalAlignment )
1175   {
1176     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1177     {
1178       mImpl->mAlignmentOffset.x = 0.f;
1179       break;
1180     }
1181     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1182     {
1183       mImpl->mAlignmentOffset.x = floorf( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1184       break;
1185     }
1186     case LayoutEngine::HORIZONTAL_ALIGN_END:
1187     {
1188       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1189       break;
1190     }
1191   }
1192
1193   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1194   switch( verticalAlignment )
1195   {
1196     case LayoutEngine::VERTICAL_ALIGN_TOP:
1197     {
1198       mImpl->mAlignmentOffset.y = 0.f;
1199       break;
1200     }
1201     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1202     {
1203       mImpl->mAlignmentOffset.y = floorf( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1204       break;
1205     }
1206     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1207     {
1208       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1209       break;
1210     }
1211   }
1212 }
1213
1214 LayoutEngine& Controller::GetLayoutEngine()
1215 {
1216   return mImpl->mLayoutEngine;
1217 }
1218
1219 View& Controller::GetView()
1220 {
1221   return mImpl->mView;
1222 }
1223
1224 void Controller::KeyboardFocusGainEvent()
1225 {
1226   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1227
1228   if( mImpl->mEventData )
1229   {
1230     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
1231         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
1232     {
1233       mImpl->ChangeState( EventData::EDITING );
1234       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
1235     }
1236
1237     if( mImpl->IsShowingPlaceholderText() )
1238     {
1239       // Show alternative placeholder-text when editing
1240       ShowPlaceholderText();
1241     }
1242
1243     mImpl->RequestRelayout();
1244   }
1245 }
1246
1247 void Controller::KeyboardFocusLostEvent()
1248 {
1249   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1250
1251   if( mImpl->mEventData )
1252   {
1253     if ( EventData::INTERRUPTED != mImpl->mEventData->mState )
1254     {
1255       mImpl->ChangeState( EventData::INACTIVE );
1256
1257       if( !mImpl->IsShowingRealText() )
1258       {
1259         // Revert to regular placeholder-text when not editing
1260         ShowPlaceholderText();
1261       }
1262     }
1263   }
1264   mImpl->RequestRelayout();
1265 }
1266
1267 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1268 {
1269   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1270
1271   bool textChanged( false );
1272
1273   if( mImpl->mEventData &&
1274       keyEvent.state == KeyEvent::Down )
1275   {
1276     int keyCode = keyEvent.keyCode;
1277     const std::string& keyString = keyEvent.keyPressed;
1278
1279     // Pre-process to separate modifying events from non-modifying input events.
1280     if( Dali::DALI_KEY_ESCAPE == keyCode )
1281     {
1282       // Escape key is a special case which causes focus loss
1283       KeyboardFocusLostEvent();
1284     }
1285     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1286              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1287              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1288              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1289     {
1290       Event event( Event::CURSOR_KEY_EVENT );
1291       event.p1.mInt = keyCode;
1292       mImpl->mEventData->mEventQueue.push_back( event );
1293     }
1294     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1295     {
1296       textChanged = BackspaceKeyEvent();
1297     }
1298     else if ( IsKey( keyEvent,  Dali::DALI_KEY_POWER ) )
1299     {
1300       mImpl->ChangeState( EventData::INTERRUPTED ); // State is not INACTIVE as expect to return to edit mode.
1301       // Avoids calling the InsertText() method which can delete selected text
1302     }
1303     else if ( IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
1304               IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
1305     {
1306       mImpl->ChangeState( EventData::INACTIVE );
1307       // Menu/Home key behaviour does not allow edit mode to resume like Power key
1308       // Avoids calling the InsertText() method which can delete selected text
1309     }
1310     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
1311     {
1312       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
1313       // and a character is typed after the type of a upper case latin character.
1314
1315       // Do nothing.
1316     }
1317     else
1318     {
1319       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
1320
1321       // IMF manager is no longer handling key-events
1322       mImpl->ClearPreEditFlag();
1323
1324       InsertText( keyString, COMMIT );
1325       textChanged = true;
1326     }
1327
1328     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
1329          ( mImpl->mEventData->mState != EventData::INACTIVE ) )
1330     {
1331       mImpl->ChangeState( EventData::EDITING );
1332     }
1333
1334     mImpl->RequestRelayout();
1335   }
1336
1337   if( textChanged )
1338   {
1339     // Do this last since it provides callbacks into application code
1340     mImpl->mControlInterface.TextChanged();
1341   }
1342
1343   return false;
1344 }
1345
1346 void Controller::InsertText( const std::string& text, Controller::InsertType type )
1347 {
1348   bool removedPrevious( false );
1349   bool maxLengthReached( false );
1350
1351   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
1352   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
1353                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
1354                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1355
1356   // TODO: At the moment the underline runs are only for pre-edit.
1357   mImpl->mVisualModel->mUnderlineRuns.Clear();
1358
1359   Vector<Character> utf32Characters;
1360   Length characterCount( 0u );
1361
1362   // Remove the previous IMF pre-edit (predicitive text)
1363   if( mImpl->mEventData &&
1364       mImpl->mEventData->mPreEditFlag &&
1365       0 != mImpl->mEventData->mPreEditLength )
1366   {
1367     CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
1368
1369     removedPrevious = RemoveText( -static_cast<int>(offset), mImpl->mEventData->mPreEditLength );
1370
1371     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
1372     mImpl->mEventData->mPreEditLength = 0;
1373   }
1374   else
1375   {
1376     // Remove the previous Selection
1377     removedPrevious = RemoveSelectedText();
1378   }
1379
1380   if( !text.empty() )
1381   {
1382     //  Convert text into UTF-32
1383     utf32Characters.Resize( text.size() );
1384
1385     // This is a bit horrible but std::string returns a (signed) char*
1386     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1387
1388     // Transform a text array encoded in utf8 into an array encoded in utf32.
1389     // It returns the actual number of characters.
1390     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1391     utf32Characters.Resize( characterCount );
1392
1393     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
1394     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
1395   }
1396
1397   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
1398   {
1399     // The placeholder text is no longer needed
1400     if( mImpl->IsShowingPlaceholderText() )
1401     {
1402       ResetText();
1403     }
1404
1405     mImpl->ChangeState( EventData::EDITING );
1406
1407     // Handle the IMF (predicitive text) state changes
1408     if( mImpl->mEventData )
1409     {
1410       if( COMMIT == type )
1411       {
1412         // IMF manager is no longer handling key-events
1413         mImpl->ClearPreEditFlag();
1414       }
1415       else // PRE_EDIT
1416       {
1417         if( !mImpl->mEventData->mPreEditFlag )
1418         {
1419           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state" );
1420
1421           // Record the start of the pre-edit text
1422           mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
1423         }
1424
1425         mImpl->mEventData->mPreEditLength = utf32Characters.Count();
1426         mImpl->mEventData->mPreEditFlag = true;
1427
1428         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1429       }
1430     }
1431
1432     const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
1433
1434     // Restrict new text to fit within Maximum characters setting
1435     Length maxSizeOfNewText = std::min ( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
1436     maxLengthReached = ( characterCount > maxSizeOfNewText );
1437
1438     // Insert at current cursor position
1439     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
1440
1441     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1442
1443     if( cursorIndex < numberOfCharactersInModel )
1444     {
1445       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1446     }
1447     else
1448     {
1449       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1450     }
1451
1452     cursorIndex += maxSizeOfNewText;
1453
1454     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
1455   }
1456
1457   if( 0u == mImpl->mLogicalModel->mText.Count() &&
1458       mImpl->IsPlaceholderAvailable() )
1459   {
1460     // Show place-holder if empty after removing the pre-edit text
1461     ShowPlaceholderText();
1462     mImpl->mEventData->mUpdateCursorPosition = true;
1463     mImpl->ClearPreEditFlag();
1464   }
1465   else if( removedPrevious ||
1466            0 != utf32Characters.Count() )
1467   {
1468     // Queue an inserted event
1469     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
1470   }
1471
1472   if( maxLengthReached )
1473   {
1474     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
1475
1476     mImpl->ResetImfManager();
1477
1478     // Do this last since it provides callbacks into application code
1479     mImpl->mControlInterface.MaxLengthReached();
1480   }
1481 }
1482
1483 bool Controller::RemoveSelectedText()
1484 {
1485   bool textRemoved( false );
1486
1487   if( EventData::SELECTING == mImpl->mEventData->mState )
1488   {
1489     std::string removedString;
1490     mImpl->RetrieveSelection( removedString, true );
1491
1492     if( !removedString.empty() )
1493     {
1494       textRemoved = true;
1495       mImpl->ChangeState( EventData::EDITING );
1496     }
1497   }
1498
1499   return textRemoved;
1500 }
1501
1502 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1503 {
1504   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1505
1506   if( NULL != mImpl->mEventData )
1507   {
1508     if( 1u == tapCount )
1509     {
1510       // This is to avoid unnecessary relayouts when tapping an empty text-field
1511       bool relayoutNeeded( false );
1512
1513       if( mImpl->IsShowingRealText() &&
1514           EventData::EDITING == mImpl->mEventData->mState )
1515       {
1516         // Show grab handle on second tap
1517         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
1518         relayoutNeeded = true;
1519       }
1520       else if( EventData::EDITING                  != mImpl->mEventData->mState &&
1521                EventData::EDITING_WITH_GRAB_HANDLE != mImpl->mEventData->mState )
1522       {
1523         if( mImpl->IsShowingPlaceholderText() &&  ! mImpl->IsFocusedPlaceholderAvailable() )
1524         {
1525           // Hide placeholder text
1526           ResetText();
1527         }
1528         // Show cursor on first tap
1529         mImpl->ChangeState( EventData::EDITING );
1530         relayoutNeeded = true;
1531       }
1532       else if( mImpl->IsShowingRealText() )
1533       {
1534         // Move the cursor
1535         relayoutNeeded = true;
1536       }
1537
1538       // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
1539       if( relayoutNeeded )
1540       {
1541         Event event( Event::TAP_EVENT );
1542         event.p1.mUint = tapCount;
1543         event.p2.mFloat = x;
1544         event.p3.mFloat = y;
1545         mImpl->mEventData->mEventQueue.push_back( event );
1546
1547         mImpl->RequestRelayout();
1548       }
1549     }
1550     else if( 2u == tapCount )
1551     {
1552       if( mImpl->mEventData->mSelectionEnabled &&
1553           mImpl->IsShowingRealText() )
1554       {
1555         SelectEvent( x, y, false );
1556       }
1557     }
1558   }
1559
1560   // Reset keyboard as tap event has occurred.
1561   mImpl->ResetImfManager();
1562 }
1563
1564 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1565 {
1566   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1567
1568   if( mImpl->mEventData )
1569   {
1570     Event event( Event::PAN_EVENT );
1571     event.p1.mInt = state;
1572     event.p2.mFloat = displacement.x;
1573     event.p3.mFloat = displacement.y;
1574     mImpl->mEventData->mEventQueue.push_back( event );
1575
1576     mImpl->RequestRelayout();
1577   }
1578 }
1579
1580 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
1581 {
1582   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
1583
1584   if( state == Gesture::Started &&
1585       mImpl->mEventData )
1586   {
1587     if( ! mImpl->IsShowingRealText() )
1588     {
1589       Event event( Event::LONG_PRESS_EVENT );
1590       event.p1.mInt = state;
1591       mImpl->mEventData->mEventQueue.push_back( event );
1592       mImpl->RequestRelayout();
1593     }
1594     else
1595     {
1596       // The 1st long-press on inactive text-field is treated as tap
1597       if( EventData::INACTIVE == mImpl->mEventData->mState )
1598       {
1599         mImpl->ChangeState( EventData::EDITING );
1600
1601         Event event( Event::TAP_EVENT );
1602         event.p1.mUint = 1;
1603         event.p2.mFloat = x;
1604         event.p3.mFloat = y;
1605         mImpl->mEventData->mEventQueue.push_back( event );
1606
1607         mImpl->RequestRelayout();
1608       }
1609       else
1610       {
1611         // Reset the imf manger to commit the pre-edit before selecting the text.
1612         mImpl->ResetImfManager();
1613
1614         SelectEvent( x, y, false );
1615       }
1616     }
1617   }
1618 }
1619
1620 void Controller::SelectEvent( float x, float y, bool selectAll )
1621 {
1622   if( mImpl->mEventData )
1623   {
1624     mImpl->ChangeState( EventData::SELECTING );
1625
1626     if( selectAll )
1627     {
1628       Event event( Event::SELECT_ALL );
1629       mImpl->mEventData->mEventQueue.push_back( event );
1630     }
1631     else
1632     {
1633       Event event( Event::SELECT );
1634       event.p2.mFloat = x;
1635       event.p3.mFloat = y;
1636       mImpl->mEventData->mEventQueue.push_back( event );
1637     }
1638
1639     mImpl->RequestRelayout();
1640   }
1641 }
1642
1643 void Controller::GetTargetSize( Vector2& targetSize )
1644 {
1645   targetSize = mImpl->mVisualModel->mControlSize;
1646 }
1647
1648 void Controller::AddDecoration( Actor& actor, bool needsClipping )
1649 {
1650   mImpl->mControlInterface.AddDecoration( actor, needsClipping );
1651 }
1652
1653 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
1654 {
1655   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
1656
1657   if( mImpl->mEventData )
1658   {
1659     switch( handleType )
1660     {
1661       case GRAB_HANDLE:
1662       {
1663         Event event( Event::GRAB_HANDLE_EVENT );
1664         event.p1.mUint  = state;
1665         event.p2.mFloat = x;
1666         event.p3.mFloat = y;
1667
1668         mImpl->mEventData->mEventQueue.push_back( event );
1669         break;
1670       }
1671       case LEFT_SELECTION_HANDLE:
1672       {
1673         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
1674         event.p1.mUint  = state;
1675         event.p2.mFloat = x;
1676         event.p3.mFloat = y;
1677
1678         mImpl->mEventData->mEventQueue.push_back( event );
1679         break;
1680       }
1681       case RIGHT_SELECTION_HANDLE:
1682       {
1683         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
1684         event.p1.mUint  = state;
1685         event.p2.mFloat = x;
1686         event.p3.mFloat = y;
1687
1688         mImpl->mEventData->mEventQueue.push_back( event );
1689         break;
1690       }
1691       case LEFT_SELECTION_HANDLE_MARKER:
1692       case RIGHT_SELECTION_HANDLE_MARKER:
1693       {
1694         // Markers do not move the handles.
1695         break;
1696       }
1697       case HANDLE_TYPE_COUNT:
1698       {
1699         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
1700       }
1701     }
1702
1703     mImpl->RequestRelayout();
1704   }
1705 }
1706
1707 void Controller::PasteText( const std::string& stringToPaste )
1708 {
1709   InsertText( stringToPaste, Text::Controller::COMMIT );
1710   mImpl->ChangeState( EventData::EDITING );
1711   mImpl->RequestRelayout();
1712 }
1713
1714 void Controller::PasteClipboardItemEvent()
1715 {
1716   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
1717   std::string stringToPaste( notifier.GetContent() );
1718   PasteText( stringToPaste );
1719 }
1720
1721 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
1722 {
1723   if( NULL == mImpl->mEventData )
1724   {
1725     return;
1726   }
1727
1728   switch( button )
1729   {
1730     case Toolkit::TextSelectionPopup::CUT:
1731     {
1732       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
1733       mImpl->mOperationsPending = ALL_OPERATIONS;
1734
1735       // This is to reset the virtual keyboard to Upper-case
1736       if( 0u == mImpl->mLogicalModel->mText.Count() )
1737       {
1738         NotifyImfManager();
1739       }
1740
1741       if( 0u != mImpl->mLogicalModel->mText.Count() ||
1742           !mImpl->IsPlaceholderAvailable() )
1743       {
1744         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1745       }
1746       else
1747       {
1748         ShowPlaceholderText();
1749         mImpl->mEventData->mUpdateCursorPosition = true;
1750       }
1751       mImpl->RequestRelayout();
1752       mImpl->mControlInterface.TextChanged();
1753       break;
1754     }
1755     case Toolkit::TextSelectionPopup::COPY:
1756     {
1757       mImpl->SendSelectionToClipboard( false ); // Text not modified
1758       mImpl->RequestRelayout(); // Handles, Selection Highlight, Popup
1759       break;
1760     }
1761     case Toolkit::TextSelectionPopup::PASTE:
1762     {
1763       std::string stringToPaste("");
1764       mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
1765       PasteText( stringToPaste );
1766       break;
1767     }
1768     case Toolkit::TextSelectionPopup::SELECT:
1769     {
1770       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
1771
1772       if( mImpl->mEventData->mSelectionEnabled  )
1773       {
1774         // Creates a SELECT event.
1775         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
1776       }
1777       break;
1778     }
1779     case Toolkit::TextSelectionPopup::SELECT_ALL:
1780     {
1781       // Creates a SELECT_ALL event
1782       SelectEvent( 0.f, 0.f, true );
1783       break;
1784     }
1785     case Toolkit::TextSelectionPopup::CLIPBOARD:
1786     {
1787       mImpl->ShowClipboard();
1788       break;
1789     }
1790     case Toolkit::TextSelectionPopup::NONE:
1791     {
1792       // Nothing to do.
1793       break;
1794     }
1795   }
1796 }
1797
1798 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
1799 {
1800   bool update( false );
1801   bool requestRelayout = false;
1802
1803   std::string text;
1804   unsigned int cursorPosition( 0 );
1805
1806   switch ( imfEvent.eventName )
1807   {
1808     case ImfManager::COMMIT:
1809     {
1810       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
1811       update=true;
1812       requestRelayout = true;
1813       break;
1814     }
1815     case ImfManager::PREEDIT:
1816     {
1817       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
1818       update = true;
1819       requestRelayout = true;
1820       break;
1821     }
1822     case ImfManager::DELETESURROUNDING:
1823     {
1824       update = RemoveText( imfEvent.cursorOffset, imfEvent.numberOfChars );
1825
1826       if( update )
1827       {
1828         if( 0u != mImpl->mLogicalModel->mText.Count() ||
1829             !mImpl->IsPlaceholderAvailable() )
1830         {
1831           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1832         }
1833         else
1834         {
1835           ShowPlaceholderText();
1836           mImpl->mEventData->mUpdateCursorPosition = true;
1837         }
1838       }
1839       requestRelayout = true;
1840       break;
1841     }
1842     case ImfManager::GETSURROUNDING:
1843     {
1844       GetText( text );
1845       cursorPosition = GetLogicalCursorPosition();
1846
1847       imfManager.SetSurroundingText( text );
1848       imfManager.SetCursorPosition( cursorPosition );
1849       break;
1850     }
1851     case ImfManager::VOID:
1852     {
1853       // do nothing
1854       break;
1855     }
1856   } // end switch
1857
1858   if( ImfManager::GETSURROUNDING != imfEvent.eventName )
1859   {
1860     GetText( text );
1861     cursorPosition = GetLogicalCursorPosition();
1862   }
1863
1864   if( requestRelayout )
1865   {
1866     mImpl->mOperationsPending = ALL_OPERATIONS;
1867     mImpl->RequestRelayout();
1868
1869     // Do this last since it provides callbacks into application code
1870     mImpl->mControlInterface.TextChanged();
1871   }
1872
1873   ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
1874
1875   return callbackData;
1876 }
1877
1878 Controller::~Controller()
1879 {
1880   delete mImpl;
1881 }
1882
1883 bool Controller::BackspaceKeyEvent()
1884 {
1885   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
1886
1887   // IMF manager is no longer handling key-events
1888   mImpl->ClearPreEditFlag();
1889
1890   bool removed( false );
1891
1892   if( EventData::SELECTING == mImpl->mEventData->mState )
1893   {
1894     removed = RemoveSelectedText();
1895   }
1896   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
1897   {
1898     // Remove the character before the current cursor position
1899     removed = RemoveText( -1, 1 );
1900   }
1901
1902   if( removed )
1903   {
1904     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE RemovedText\n", this );
1905     // Notifiy the IMF manager after text changed
1906     // Automatic  Upper-case and restarting prediction on an existing word require this.
1907     NotifyImfManager();
1908
1909     if( 0u != mImpl->mLogicalModel->mText.Count() ||
1910         !mImpl->IsPlaceholderAvailable() )
1911     {
1912       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1913     }
1914     else
1915     {
1916       ShowPlaceholderText();
1917       mImpl->mEventData->mUpdateCursorPosition = true;
1918     }
1919   }
1920
1921   return removed;
1922 }
1923
1924 void Controller::NotifyImfManager()
1925 {
1926   if( mImpl->mEventData )
1927   {
1928     ImfManager imfManager = ImfManager::Get();
1929
1930     if( imfManager )
1931     {
1932       // Notifying IMF of a cursor change triggers a surrounding text request so updating it now.
1933       std::string text;
1934       GetText( text );
1935       imfManager.SetSurroundingText( text );
1936
1937       imfManager.SetCursorPosition( GetLogicalCursorPosition() );
1938       imfManager.NotifyCursorPosition();
1939     }
1940   }
1941 }
1942
1943 void Controller::ShowPlaceholderText()
1944 {
1945   if( mImpl->IsPlaceholderAvailable() )
1946   {
1947     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
1948
1949     mImpl->mEventData->mIsShowingPlaceholderText = true;
1950
1951     // Disable handles when showing place-holder text
1952     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1953     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1954     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1955
1956     const char* text( NULL );
1957     size_t size( 0 );
1958
1959     // TODO - Switch placeholder text styles when changing state
1960     if( EventData::INACTIVE != mImpl->mEventData->mState &&
1961         0u != mImpl->mEventData->mPlaceholderTextActive.c_str() )
1962     {
1963       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
1964       size = mImpl->mEventData->mPlaceholderTextActive.size();
1965     }
1966     else
1967     {
1968       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
1969       size = mImpl->mEventData->mPlaceholderTextInactive.size();
1970     }
1971
1972     // Reset model for showing placeholder.
1973     mImpl->mLogicalModel->mText.Clear();
1974     ClearModelData();
1975     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
1976
1977     // Convert text into UTF-32
1978     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1979     utf32Characters.Resize( size );
1980
1981     // This is a bit horrible but std::string returns a (signed) char*
1982     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
1983
1984     // Transform a text array encoded in utf8 into an array encoded in utf32.
1985     // It returns the actual number of characters.
1986     Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
1987     utf32Characters.Resize( characterCount );
1988
1989     // Reset the cursor position
1990     mImpl->mEventData->mPrimaryCursorPosition = 0;
1991
1992     // The natural size needs to be re-calculated.
1993     mImpl->mRecalculateNaturalSize = true;
1994
1995     // Apply modifications to the model
1996     mImpl->mOperationsPending = ALL_OPERATIONS;
1997
1998     // Update the rest of the model during size negotiation
1999     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
2000   }
2001 }
2002
2003 void Controller::ClearModelData()
2004 {
2005   // n.b. This does not Clear the mText from mLogicalModel
2006   mImpl->mLogicalModel->mScriptRuns.Clear();
2007   mImpl->mLogicalModel->mFontRuns.Clear();
2008   mImpl->mLogicalModel->mLineBreakInfo.Clear();
2009   mImpl->mLogicalModel->mWordBreakInfo.Clear();
2010   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
2011   mImpl->mLogicalModel->mCharacterDirections.Clear();
2012   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
2013   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
2014   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
2015   mImpl->mVisualModel->mGlyphs.Clear();
2016   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
2017   mImpl->mVisualModel->mCharactersToGlyph.Clear();
2018   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
2019   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
2020   mImpl->mVisualModel->mGlyphPositions.Clear();
2021   mImpl->mVisualModel->mLines.Clear();
2022   mImpl->mVisualModel->ClearCaches();
2023 }
2024
2025 void Controller::ClearFontData()
2026 {
2027   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
2028   mImpl->mLogicalModel->mFontRuns.Clear();
2029   mImpl->mVisualModel->mGlyphs.Clear();
2030   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
2031   mImpl->mVisualModel->mCharactersToGlyph.Clear();
2032   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
2033   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
2034   mImpl->mVisualModel->mGlyphPositions.Clear();
2035   mImpl->mVisualModel->mLines.Clear();
2036   mImpl->mVisualModel->ClearCaches();
2037 }
2038
2039 Controller::Controller( ControlInterface& controlInterface )
2040 : mImpl( NULL )
2041 {
2042   mImpl = new Controller::Impl( controlInterface );
2043 }
2044
2045 } // namespace Text
2046
2047 } // namespace Toolkit
2048
2049 } // namespace Dali