Fixed overlapping issue between cursor and placeholder text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller.h>
20
21 // 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::SELECTION_CHANGED == mImpl->mEventData->mState )  ||
93         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
94         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
95     {
96       mImpl->ChangeState( EventData::EDITING );
97     }
98   }
99
100   if( !text.empty() )
101   {
102     //  Convert text into UTF-32
103     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
104     utf32Characters.Resize( text.size() );
105
106     // This is a bit horrible but std::string returns a (signed) char*
107     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
108
109     // Transform a text array encoded in utf8 into an array encoded in utf32.
110     // It returns the actual number of characters.
111     Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
112     utf32Characters.Resize( characterCount );
113
114     DALI_ASSERT_DEBUG( text.size() >= characterCount && "Invalid UTF32 conversion length" );
115     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, text.size(), mImpl->mLogicalModel->mText.Count() );
116
117     // To reset the cursor position
118     lastCursorIndex = characterCount;
119
120     // Update the rest of the model during size negotiation
121     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
122
123     // The natural size needs to be re-calculated.
124     mImpl->mRecalculateNaturalSize = true;
125
126     // Apply modifications to the model
127     mImpl->mOperationsPending = ALL_OPERATIONS;
128   }
129   else
130   {
131     ShowPlaceholderText();
132   }
133
134   // Resets the cursor position.
135   ResetCursorPosition( lastCursorIndex );
136
137   // Scrolls the text to make the cursor visible.
138   ResetScrollPosition();
139
140   mImpl->RequestRelayout();
141
142   if( mImpl->mEventData )
143   {
144     // Cancel previously queued events
145     mImpl->mEventData->mEventQueue.clear();
146   }
147
148   // Notify IMF as text changed
149   NotifyImfManager();
150
151   // Do this last since it provides callbacks into application code
152   mImpl->mControlInterface.TextChanged();
153 }
154
155 void Controller::GetText( std::string& text ) const
156 {
157   if( ! mImpl->IsShowingPlaceholderText() )
158   {
159     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
160
161     if( 0u != utf32Characters.Count() )
162     {
163       Utf32ToUtf8( &utf32Characters[0], utf32Characters.Count(), text );
164     }
165   }
166   else
167   {
168     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
169   }
170 }
171
172 unsigned int Controller::GetLogicalCursorPosition() const
173 {
174   if( mImpl->mEventData )
175   {
176     return mImpl->mEventData->mPrimaryCursorPosition;
177   }
178
179   return 0u;
180 }
181
182 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
183 {
184   if( mImpl->mEventData )
185   {
186     if( PLACEHOLDER_TYPE_INACTIVE == type )
187     {
188       mImpl->mEventData->mPlaceholderTextInactive = text;
189     }
190     else
191     {
192       mImpl->mEventData->mPlaceholderTextActive = text;
193     }
194
195     // Update placeholder if there is no text
196     if( mImpl->IsShowingPlaceholderText() ||
197         0u == mImpl->mLogicalModel->mText.Count() )
198     {
199       ShowPlaceholderText();
200     }
201   }
202 }
203
204 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
205 {
206   if( mImpl->mEventData )
207   {
208     if( PLACEHOLDER_TYPE_INACTIVE == type )
209     {
210       text = mImpl->mEventData->mPlaceholderTextInactive;
211     }
212     else
213     {
214       text = mImpl->mEventData->mPlaceholderTextActive;
215     }
216   }
217 }
218
219 void Controller::SetMaximumNumberOfCharacters( int maxCharacters )
220 {
221   if ( maxCharacters >= 0 )
222   {
223     mImpl->mMaximumNumberOfCharacters = maxCharacters;
224   }
225 }
226
227 int Controller::GetMaximumNumberOfCharacters()
228 {
229   return mImpl->mMaximumNumberOfCharacters;
230 }
231
232 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily, bool userDefined )
233 {
234   if( !mImpl->mFontDefaults )
235   {
236     mImpl->mFontDefaults = new FontDefaults();
237   }
238
239   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
240   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s userDefined: %s\n", defaultFontFamily.c_str(), userDefined ? "true":"false" );
241   mImpl->mUserDefinedFontFamily = userDefined;
242
243   // Clear the font-specific data
244   ClearFontData();
245
246   mImpl->mOperationsPending = ALL_OPERATIONS;
247   mImpl->mRecalculateNaturalSize = true;
248
249   mImpl->RequestRelayout();
250 }
251
252 const std::string& Controller::GetDefaultFontFamily() const
253 {
254   if( mImpl->mFontDefaults )
255   {
256     return mImpl->mFontDefaults->mFontDescription.family;
257   }
258
259   return EMPTY_STRING;
260 }
261
262 void Controller::SetDefaultFontStyle( const std::string& style )
263 {
264   if( !mImpl->mFontDefaults )
265   {
266     mImpl->mFontDefaults = new FontDefaults();
267   }
268
269   mImpl->mFontDefaults->mFontStyle = style;
270 }
271
272 const std::string& Controller::GetDefaultFontStyle() const
273 {
274   if( mImpl->mFontDefaults )
275   {
276     return mImpl->mFontDefaults->mFontStyle;
277   }
278
279   return EMPTY_STRING;
280 }
281
282 void Controller::SetDefaultFontWidth( FontWidth width )
283 {
284   if( !mImpl->mFontDefaults )
285   {
286     mImpl->mFontDefaults = new FontDefaults();
287   }
288
289   mImpl->mFontDefaults->mFontDescription.width = width;
290
291   // Clear the font-specific data
292   ClearFontData();
293
294   mImpl->mOperationsPending = ALL_OPERATIONS;
295   mImpl->mRecalculateNaturalSize = true;
296
297   mImpl->RequestRelayout();
298 }
299
300 FontWidth Controller::GetDefaultFontWidth() const
301 {
302   if( mImpl->mFontDefaults )
303   {
304     return mImpl->mFontDefaults->mFontDescription.width;
305   }
306
307   return TextAbstraction::FontWidth::NORMAL;
308 }
309
310 void Controller::SetDefaultFontWeight( FontWeight weight )
311 {
312   if( !mImpl->mFontDefaults )
313   {
314     mImpl->mFontDefaults = new FontDefaults();
315   }
316
317   mImpl->mFontDefaults->mFontDescription.weight = weight;
318
319   // Clear the font-specific data
320   ClearFontData();
321
322   mImpl->mOperationsPending = ALL_OPERATIONS;
323   mImpl->mRecalculateNaturalSize = true;
324
325   mImpl->RequestRelayout();
326 }
327
328 FontWeight Controller::GetDefaultFontWeight() const
329 {
330   if( mImpl->mFontDefaults )
331   {
332     return mImpl->mFontDefaults->mFontDescription.weight;
333   }
334
335   return TextAbstraction::FontWeight::NORMAL;
336 }
337
338 void Controller::SetDefaultFontSlant( FontSlant slant )
339 {
340   if( !mImpl->mFontDefaults )
341   {
342     mImpl->mFontDefaults = new FontDefaults();
343   }
344
345   mImpl->mFontDefaults->mFontDescription.slant = slant;
346
347   // Clear the font-specific data
348   ClearFontData();
349
350   mImpl->mOperationsPending = ALL_OPERATIONS;
351   mImpl->mRecalculateNaturalSize = true;
352
353   mImpl->RequestRelayout();
354 }
355
356 FontSlant Controller::GetDefaultFontSlant() const
357 {
358   if( mImpl->mFontDefaults )
359   {
360     return mImpl->mFontDefaults->mFontDescription.slant;
361   }
362
363   return TextAbstraction::FontSlant::NORMAL;
364 }
365
366 void Controller::SetDefaultPointSize( float pointSize )
367 {
368   if( !mImpl->mFontDefaults )
369   {
370     mImpl->mFontDefaults = new FontDefaults();
371   }
372
373   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
374
375   unsigned int horizontalDpi( 0u );
376   unsigned int verticalDpi( 0u );
377   mImpl->mFontClient.GetDpi( horizontalDpi, verticalDpi );
378
379   // Adjust the metrics if the fixed-size font should be down-scaled
380   int maxEmojiSize( pointSize/POINTS_PER_INCH * verticalDpi );
381   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultPointSize %p setting MaxEmojiSize %d\n", this, maxEmojiSize );
382   mImpl->mMetrics->SetMaxEmojiSize( maxEmojiSize );
383
384   // Clear the font-specific data
385   ClearFontData();
386
387   mImpl->mOperationsPending = ALL_OPERATIONS;
388   mImpl->mRecalculateNaturalSize = true;
389
390   mImpl->RequestRelayout();
391 }
392
393 float Controller::GetDefaultPointSize() const
394 {
395   if( mImpl->mFontDefaults )
396   {
397     return mImpl->mFontDefaults->mDefaultPointSize;
398   }
399
400   return 0.0f;
401 }
402
403 void Controller::UpdateAfterFontChange( std::string& newDefaultFont )
404 {
405   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange");
406
407   ClearFontData();
408
409   if ( !mImpl->mUserDefinedFontFamily ) // If user defined font then should not update when system font changes
410   {
411     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
412     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
413     mImpl->UpdateModel( ALL_OPERATIONS );
414     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
415     mImpl->mRecalculateNaturalSize = true;
416     mImpl->RequestRelayout();
417   }
418 }
419
420 void Controller::SetTextColor( const Vector4& textColor )
421 {
422   mImpl->mTextColor = textColor;
423
424   if( !mImpl->IsShowingPlaceholderText() )
425   {
426     mImpl->mVisualModel->SetTextColor( textColor );
427
428     mImpl->RequestRelayout();
429   }
430 }
431
432 const Vector4& Controller::GetTextColor() const
433 {
434   return mImpl->mTextColor;
435 }
436
437 bool Controller::RemoveText( int cursorOffset, int numberOfChars )
438 {
439   bool removed( false );
440
441   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfChars %d\n",
442                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfChars );
443
444   if( !mImpl->IsShowingPlaceholderText() )
445   {
446     // Delete at current cursor position
447     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
448     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
449
450     CharacterIndex cursorIndex = oldCursorIndex;
451
452     // Validate the cursor position & number of characters
453     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
454     {
455       cursorIndex = oldCursorIndex + cursorOffset;
456     }
457
458     if( (cursorIndex + numberOfChars) > currentText.Count() )
459     {
460       numberOfChars = currentText.Count() - cursorIndex;
461     }
462
463     if( (cursorIndex + numberOfChars) <= currentText.Count() )
464     {
465       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
466       Vector<Character>::Iterator last  = first + numberOfChars;
467
468       currentText.Erase( first, last );
469
470       // Cursor position retreat
471       oldCursorIndex = cursorIndex;
472
473       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfChars );
474       removed = true;
475     }
476   }
477
478   return removed;
479 }
480
481 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
482 {
483   if( mImpl->mEventData )
484   {
485     mImpl->mEventData->mPlaceholderTextColor = textColor;
486   }
487
488   if( mImpl->IsShowingPlaceholderText() )
489   {
490     mImpl->mVisualModel->SetTextColor( textColor );
491     mImpl->RequestRelayout();
492   }
493 }
494
495 const Vector4& Controller::GetPlaceholderTextColor() const
496 {
497   if( mImpl->mEventData )
498   {
499     return mImpl->mEventData->mPlaceholderTextColor;
500   }
501
502   return Color::BLACK;
503 }
504
505 void Controller::SetShadowOffset( const Vector2& shadowOffset )
506 {
507   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
508
509   mImpl->RequestRelayout();
510 }
511
512 const Vector2& Controller::GetShadowOffset() const
513 {
514   return mImpl->mVisualModel->GetShadowOffset();
515 }
516
517 void Controller::SetShadowColor( const Vector4& shadowColor )
518 {
519   mImpl->mVisualModel->SetShadowColor( shadowColor );
520
521   mImpl->RequestRelayout();
522 }
523
524 const Vector4& Controller::GetShadowColor() const
525 {
526   return mImpl->mVisualModel->GetShadowColor();
527 }
528
529 void Controller::SetUnderlineColor( const Vector4& color )
530 {
531   mImpl->mVisualModel->SetUnderlineColor( color );
532
533   mImpl->RequestRelayout();
534 }
535
536 const Vector4& Controller::GetUnderlineColor() const
537 {
538   return mImpl->mVisualModel->GetUnderlineColor();
539 }
540
541 void Controller::SetUnderlineEnabled( bool enabled )
542 {
543   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
544
545   mImpl->RequestRelayout();
546 }
547
548 bool Controller::IsUnderlineEnabled() const
549 {
550   return mImpl->mVisualModel->IsUnderlineEnabled();
551 }
552
553 void Controller::SetUnderlineHeight( float height )
554 {
555   mImpl->mVisualModel->SetUnderlineHeight( height );
556
557   mImpl->RequestRelayout();
558 }
559
560 float Controller::GetUnderlineHeight() const
561 {
562   return mImpl->mVisualModel->GetUnderlineHeight();
563 }
564
565 void Controller::SetEnableCursorBlink( bool enable )
566 {
567   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
568
569   if( mImpl->mEventData )
570   {
571     mImpl->mEventData->mCursorBlinkEnabled = enable;
572
573     if( !enable &&
574         mImpl->mEventData->mDecorator )
575     {
576       mImpl->mEventData->mDecorator->StopCursorBlink();
577     }
578   }
579 }
580
581 bool Controller::GetEnableCursorBlink() const
582 {
583   if( mImpl->mEventData )
584   {
585     return mImpl->mEventData->mCursorBlinkEnabled;
586   }
587
588   return false;
589 }
590
591 const Vector2& Controller::GetScrollPosition() const
592 {
593   if( mImpl->mEventData )
594   {
595     return mImpl->mEventData->mScrollPosition;
596   }
597
598   return Vector2::ZERO;
599 }
600
601 const Vector2& Controller::GetAlignmentOffset() const
602 {
603   return mImpl->mAlignmentOffset;
604 }
605
606 Vector3 Controller::GetNaturalSize()
607 {
608   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
609   Vector3 naturalSize;
610
611   // Make sure the model is up-to-date before layouting
612   ProcessModifyEvents();
613
614   if( mImpl->mRecalculateNaturalSize )
615   {
616     // Operations that can be done only once until the text changes.
617     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
618                                                                            GET_SCRIPTS       |
619                                                                            VALIDATE_FONTS    |
620                                                                            GET_LINE_BREAKS   |
621                                                                            GET_WORD_BREAKS   |
622                                                                            BIDI_INFO         |
623                                                                            SHAPE_TEXT        |
624                                                                            GET_GLYPH_METRICS );
625     // Make sure the model is up-to-date before layouting
626     mImpl->UpdateModel( onlyOnceOperations );
627
628     // Operations that need to be done if the size changes.
629     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
630                                                                         ALIGN  |
631                                                                         REORDER );
632
633     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
634                 static_cast<OperationsMask>( onlyOnceOperations |
635                                              sizeOperations ),
636                 naturalSize.GetVectorXY() );
637
638     // Do not do again the only once operations.
639     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
640
641     // Do the size related operations again.
642     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
643
644     // Stores the natural size to avoid recalculate it again
645     // unless the text/style changes.
646     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
647
648     mImpl->mRecalculateNaturalSize = false;
649
650     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
651   }
652   else
653   {
654     naturalSize = mImpl->mVisualModel->GetNaturalSize();
655
656     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
657   }
658
659   naturalSize.x = ConvertToEven( naturalSize.x );
660   naturalSize.y = ConvertToEven( naturalSize.y );
661
662   return naturalSize;
663 }
664
665 float Controller::GetHeightForWidth( float width )
666 {
667   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
668   // Make sure the model is up-to-date before layouting
669   ProcessModifyEvents();
670
671   Size layoutSize;
672   if( width != mImpl->mVisualModel->mControlSize.width )
673   {
674     // Operations that can be done only once until the text changes.
675     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
676                                                                            GET_SCRIPTS       |
677                                                                            VALIDATE_FONTS    |
678                                                                            GET_LINE_BREAKS   |
679                                                                            GET_WORD_BREAKS   |
680                                                                            BIDI_INFO         |
681                                                                            SHAPE_TEXT        |
682                                                                            GET_GLYPH_METRICS );
683     // Make sure the model is up-to-date before layouting
684     mImpl->UpdateModel( onlyOnceOperations );
685
686     // Operations that need to be done if the size changes.
687     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
688                                                                         ALIGN  |
689                                                                         REORDER );
690
691     DoRelayout( Size( width, MAX_FLOAT ),
692                 static_cast<OperationsMask>( onlyOnceOperations |
693                                              sizeOperations ),
694                 layoutSize );
695
696     // Do not do again the only once operations.
697     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
698
699     // Do the size related operations again.
700     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
701     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
702   }
703   else
704   {
705     layoutSize = mImpl->mVisualModel->GetActualSize();
706     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
707   }
708
709   return layoutSize.height;
710 }
711
712 bool Controller::Relayout( const Size& size )
713 {
714   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f\n", this, size.width, size.height );
715
716   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
717   {
718     bool glyphsRemoved( false );
719     if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
720     {
721       mImpl->mVisualModel->mGlyphPositions.Clear();
722       glyphsRemoved = true;
723     }
724     // Not worth to relayout if width or height is equal to zero.
725     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
726     return glyphsRemoved;
727   }
728
729   if( size != mImpl->mVisualModel->mControlSize )
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.
756   Vector2 offset;
757   if( 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 there is a nex size, the scroll position needs to be clamped.
768     mImpl->ClampHorizontalScroll( layoutSize );
769
770     // Update the decorator's positions.
771     mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
772
773     // Move the cursor, grab handle etc.
774     updated = mImpl->ProcessInputEvents() || updated;
775   }
776
777   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
778   return updated;
779 }
780
781 void Controller::ProcessModifyEvents()
782 {
783   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
784
785   for( unsigned int i=0; i<events.size(); ++i )
786   {
787     if( ModifyEvent::TEXT_REPLACED == events[0].type )
788     {
789       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
790       DALI_ASSERT_DEBUG( 0 == i && "Unexpected TEXT_REPLACED event" );
791
792       TextReplacedEvent();
793     }
794     else if( ModifyEvent::TEXT_INSERTED == events[0].type )
795     {
796       TextInsertedEvent();
797     }
798     else if( ModifyEvent::TEXT_DELETED == events[0].type )
799     {
800       // Placeholder-text cannot be deleted
801       if( !mImpl->IsShowingPlaceholderText() )
802       {
803         TextDeletedEvent();
804       }
805     }
806   }
807
808   if( mImpl->mEventData &&
809       0 != events.size() )
810   {
811     // When the text is being modified, delay cursor blinking
812     mImpl->mEventData->mDecorator->DelayCursorBlink();
813   }
814
815   // Discard temporary text
816   events.clear();
817 }
818
819 void Controller::ResetText()
820 {
821   // Reset buffers.
822   mImpl->mLogicalModel->mText.Clear();
823   ClearModelData();
824
825   // We have cleared everything including the placeholder-text
826   mImpl->PlaceholderCleared();
827
828   // The natural size needs to be re-calculated.
829   mImpl->mRecalculateNaturalSize = true;
830
831   // Apply modifications to the model
832   mImpl->mOperationsPending = ALL_OPERATIONS;
833 }
834
835 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
836 {
837   // Reset the cursor position
838   if( NULL != mImpl->mEventData )
839   {
840     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
841
842     // Update the cursor if it's in editing mode.
843     if( ( EventData::EDITING == mImpl->mEventData->mState )            ||
844         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
845         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
846     {
847       mImpl->mEventData->mUpdateCursorPosition = true;
848     }
849   }
850 }
851
852 void Controller::ResetScrollPosition()
853 {
854   if( NULL != mImpl->mEventData )
855   {
856     // Reset the scroll position.
857     mImpl->mEventData->mScrollPosition = Vector2::ZERO;
858     mImpl->mEventData->mScrollAfterUpdatePosition = true;
859   }
860 }
861
862 void Controller::TextReplacedEvent()
863 {
864   // Reset buffers.
865   ClearModelData();
866
867   // The natural size needs to be re-calculated.
868   mImpl->mRecalculateNaturalSize = true;
869
870   // Apply modifications to the model
871   mImpl->mOperationsPending = ALL_OPERATIONS;
872   mImpl->UpdateModel( ALL_OPERATIONS );
873   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
874                                                            ALIGN              |
875                                                            UPDATE_ACTUAL_SIZE |
876                                                            REORDER );
877 }
878
879 void Controller::TextInsertedEvent()
880 {
881   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
882
883   // TODO - Optimize this
884   ClearModelData();
885
886   // The natural size needs to be re-calculated.
887   mImpl->mRecalculateNaturalSize = true;
888
889   // Apply modifications to the model; TODO - Optimize this
890   mImpl->mOperationsPending = ALL_OPERATIONS;
891   mImpl->UpdateModel( ALL_OPERATIONS );
892   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
893                                                            ALIGN              |
894                                                            UPDATE_ACTUAL_SIZE |
895                                                            REORDER );
896
897   // Queue a cursor reposition event; this must wait until after DoRelayout()
898   if( ( EventData::EDITING == mImpl->mEventData->mState )            ||
899       ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
900       ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
901   {
902     mImpl->mEventData->mUpdateCursorPosition = true;
903     mImpl->mEventData->mScrollAfterUpdatePosition = true;
904   }
905 }
906
907 void Controller::TextDeletedEvent()
908 {
909   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
910
911   // TODO - Optimize this
912   ClearModelData();
913
914   // The natural size needs to be re-calculated.
915   mImpl->mRecalculateNaturalSize = true;
916
917   // Apply modifications to the model; TODO - Optimize this
918   mImpl->mOperationsPending = ALL_OPERATIONS;
919   mImpl->UpdateModel( ALL_OPERATIONS );
920   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
921                                                            ALIGN              |
922                                                            UPDATE_ACTUAL_SIZE |
923                                                            REORDER );
924
925   // Queue a cursor reposition event; this must wait until after DoRelayout()
926   if( 0u == mImpl->mLogicalModel->mText.Count() )
927   {
928     mImpl->mEventData->mUpdateCursorPosition = true;
929   }
930   else
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       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1184       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
1185       break;
1186     }
1187     case LayoutEngine::HORIZONTAL_ALIGN_END:
1188     {
1189       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1190       break;
1191     }
1192   }
1193
1194   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1195   switch( verticalAlignment )
1196   {
1197     case LayoutEngine::VERTICAL_ALIGN_TOP:
1198     {
1199       mImpl->mAlignmentOffset.y = 0.f;
1200       break;
1201     }
1202     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1203     {
1204       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1205       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
1206       break;
1207     }
1208     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1209     {
1210       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1211       break;
1212     }
1213   }
1214 }
1215
1216 LayoutEngine& Controller::GetLayoutEngine()
1217 {
1218   return mImpl->mLayoutEngine;
1219 }
1220
1221 View& Controller::GetView()
1222 {
1223   return mImpl->mView;
1224 }
1225
1226 void Controller::KeyboardFocusGainEvent()
1227 {
1228   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1229
1230   if( mImpl->mEventData )
1231   {
1232     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
1233         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
1234     {
1235       mImpl->ChangeState( EventData::EDITING );
1236       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
1237     }
1238
1239     if( mImpl->IsShowingPlaceholderText() )
1240     {
1241       // Show alternative placeholder-text when editing
1242       ShowPlaceholderText();
1243     }
1244
1245     mImpl->RequestRelayout();
1246   }
1247 }
1248
1249 void Controller::KeyboardFocusLostEvent()
1250 {
1251   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1252
1253   if( mImpl->mEventData )
1254   {
1255     if ( EventData::INTERRUPTED != mImpl->mEventData->mState )
1256     {
1257       mImpl->ChangeState( EventData::INACTIVE );
1258
1259       if( !mImpl->IsShowingRealText() )
1260       {
1261         // Revert to regular placeholder-text when not editing
1262         ShowPlaceholderText();
1263       }
1264     }
1265   }
1266   mImpl->RequestRelayout();
1267 }
1268
1269 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1270 {
1271   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1272
1273   bool textChanged( false );
1274
1275   if( mImpl->mEventData &&
1276       keyEvent.state == KeyEvent::Down )
1277   {
1278     int keyCode = keyEvent.keyCode;
1279     const std::string& keyString = keyEvent.keyPressed;
1280
1281     // Pre-process to separate modifying events from non-modifying input events.
1282     if( Dali::DALI_KEY_ESCAPE == keyCode )
1283     {
1284       // Escape key is a special case which causes focus loss
1285       KeyboardFocusLostEvent();
1286     }
1287     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1288              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1289              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1290              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1291     {
1292       Event event( Event::CURSOR_KEY_EVENT );
1293       event.p1.mInt = keyCode;
1294       mImpl->mEventData->mEventQueue.push_back( event );
1295     }
1296     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1297     {
1298       textChanged = BackspaceKeyEvent();
1299     }
1300     else if ( IsKey( keyEvent,  Dali::DALI_KEY_POWER ) )
1301     {
1302       mImpl->ChangeState( EventData::INTERRUPTED ); // State is not INACTIVE as expect to return to edit mode.
1303       // Avoids calling the InsertText() method which can delete selected text
1304     }
1305     else if ( IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
1306               IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
1307     {
1308       mImpl->ChangeState( EventData::INACTIVE );
1309       // Menu/Home key behaviour does not allow edit mode to resume like Power key
1310       // Avoids calling the InsertText() method which can delete selected text
1311     }
1312     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
1313     {
1314       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
1315       // and a character is typed after the type of a upper case latin character.
1316
1317       // Do nothing.
1318     }
1319     else
1320     {
1321       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
1322
1323       // IMF manager is no longer handling key-events
1324       mImpl->ClearPreEditFlag();
1325
1326       InsertText( keyString, COMMIT );
1327       textChanged = true;
1328     }
1329
1330     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
1331          ( mImpl->mEventData->mState != EventData::INACTIVE ) )
1332     {
1333       mImpl->ChangeState( EventData::EDITING );
1334     }
1335
1336     mImpl->RequestRelayout();
1337   }
1338
1339   if( textChanged )
1340   {
1341     // Do this last since it provides callbacks into application code
1342     mImpl->mControlInterface.TextChanged();
1343   }
1344
1345   return false;
1346 }
1347
1348 void Controller::InsertText( const std::string& text, Controller::InsertType type )
1349 {
1350   bool removedPrevious( false );
1351   bool maxLengthReached( false );
1352
1353   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
1354   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
1355                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
1356                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1357
1358   // TODO: At the moment the underline runs are only for pre-edit.
1359   mImpl->mVisualModel->mUnderlineRuns.Clear();
1360
1361   Vector<Character> utf32Characters;
1362   Length characterCount( 0u );
1363
1364   // Remove the previous IMF pre-edit (predicitive text)
1365   if( mImpl->mEventData &&
1366       mImpl->mEventData->mPreEditFlag &&
1367       0 != mImpl->mEventData->mPreEditLength )
1368   {
1369     CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
1370
1371     removedPrevious = RemoveText( -static_cast<int>(offset), mImpl->mEventData->mPreEditLength );
1372
1373     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
1374     mImpl->mEventData->mPreEditLength = 0;
1375   }
1376   else
1377   {
1378     // Remove the previous Selection
1379     removedPrevious = RemoveSelectedText();
1380   }
1381
1382   if( !text.empty() )
1383   {
1384     //  Convert text into UTF-32
1385     utf32Characters.Resize( text.size() );
1386
1387     // This is a bit horrible but std::string returns a (signed) char*
1388     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1389
1390     // Transform a text array encoded in utf8 into an array encoded in utf32.
1391     // It returns the actual number of characters.
1392     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1393     utf32Characters.Resize( characterCount );
1394
1395     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
1396     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
1397   }
1398
1399   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
1400   {
1401     // The placeholder text is no longer needed
1402     if( mImpl->IsShowingPlaceholderText() )
1403     {
1404       ResetText();
1405     }
1406
1407     mImpl->ChangeState( EventData::EDITING );
1408
1409     // Handle the IMF (predicitive text) state changes
1410     if( mImpl->mEventData )
1411     {
1412       if( COMMIT == type )
1413       {
1414         // IMF manager is no longer handling key-events
1415         mImpl->ClearPreEditFlag();
1416       }
1417       else // PRE_EDIT
1418       {
1419         if( !mImpl->mEventData->mPreEditFlag )
1420         {
1421           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state" );
1422
1423           // Record the start of the pre-edit text
1424           mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
1425         }
1426
1427         mImpl->mEventData->mPreEditLength = utf32Characters.Count();
1428         mImpl->mEventData->mPreEditFlag = true;
1429
1430         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1431       }
1432     }
1433
1434     const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
1435
1436     // Restrict new text to fit within Maximum characters setting
1437     Length maxSizeOfNewText = std::min ( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
1438     maxLengthReached = ( characterCount > maxSizeOfNewText );
1439
1440     // Insert at current cursor position
1441     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
1442
1443     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1444
1445     if( cursorIndex < numberOfCharactersInModel )
1446     {
1447       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1448     }
1449     else
1450     {
1451       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1452     }
1453
1454     cursorIndex += maxSizeOfNewText;
1455
1456     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
1457   }
1458
1459   if( 0u == mImpl->mLogicalModel->mText.Count() &&
1460       mImpl->IsPlaceholderAvailable() )
1461   {
1462     // Show place-holder if empty after removing the pre-edit text
1463     ShowPlaceholderText();
1464     mImpl->mEventData->mUpdateCursorPosition = true;
1465     mImpl->ClearPreEditFlag();
1466   }
1467   else if( removedPrevious ||
1468            0 != utf32Characters.Count() )
1469   {
1470     // Queue an inserted event
1471     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
1472   }
1473
1474   if( maxLengthReached )
1475   {
1476     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
1477
1478     mImpl->ResetImfManager();
1479
1480     // Do this last since it provides callbacks into application code
1481     mImpl->mControlInterface.MaxLengthReached();
1482   }
1483 }
1484
1485 bool Controller::RemoveSelectedText()
1486 {
1487   bool textRemoved( false );
1488
1489   if ( EventData::SELECTING         == mImpl->mEventData->mState ||
1490        EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
1491   {
1492     std::string removedString;
1493     mImpl->RetrieveSelection( removedString, true );
1494
1495     if( !removedString.empty() )
1496     {
1497       textRemoved = true;
1498       mImpl->ChangeState( EventData::EDITING );
1499     }
1500   }
1501
1502   return textRemoved;
1503 }
1504
1505 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1506 {
1507   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1508
1509   if( NULL != mImpl->mEventData )
1510   {
1511     if( 1u == tapCount )
1512     {
1513       // This is to avoid unnecessary relayouts when tapping an empty text-field
1514       bool relayoutNeeded( false );
1515
1516       if( mImpl->IsShowingRealText() &&
1517           EventData::EDITING == mImpl->mEventData->mState )
1518       {
1519         // Show grab handle on second tap
1520         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
1521         relayoutNeeded = true;
1522       }
1523       else if( EventData::EDITING                  != mImpl->mEventData->mState &&
1524                EventData::EDITING_WITH_GRAB_HANDLE != mImpl->mEventData->mState )
1525       {
1526         if( mImpl->IsShowingPlaceholderText() &&  ! mImpl->IsFocusedPlaceholderAvailable() )
1527         {
1528           // Hide placeholder text
1529           ResetText();
1530         }
1531         // Show cursor on first tap
1532         mImpl->ChangeState( EventData::EDITING );
1533         relayoutNeeded = true;
1534       }
1535       else if( mImpl->IsShowingRealText() )
1536       {
1537         // Move the cursor
1538         relayoutNeeded = true;
1539       }
1540
1541       // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
1542       if( relayoutNeeded )
1543       {
1544         Event event( Event::TAP_EVENT );
1545         event.p1.mUint = tapCount;
1546         event.p2.mFloat = x;
1547         event.p3.mFloat = y;
1548         mImpl->mEventData->mEventQueue.push_back( event );
1549
1550         mImpl->RequestRelayout();
1551       }
1552     }
1553     else if( 2u == tapCount )
1554     {
1555       if( mImpl->mEventData->mSelectionEnabled &&
1556           mImpl->IsShowingRealText() )
1557       {
1558         SelectEvent( x, y, false );
1559       }
1560     }
1561   }
1562
1563   // Reset keyboard as tap event has occurred.
1564   mImpl->ResetImfManager();
1565 }
1566
1567 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1568 {
1569   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1570
1571   if( mImpl->mEventData )
1572   {
1573     Event event( Event::PAN_EVENT );
1574     event.p1.mInt = state;
1575     event.p2.mFloat = displacement.x;
1576     event.p3.mFloat = displacement.y;
1577     mImpl->mEventData->mEventQueue.push_back( event );
1578
1579     mImpl->RequestRelayout();
1580   }
1581 }
1582
1583 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
1584 {
1585   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
1586
1587   if( state == Gesture::Started &&
1588       mImpl->mEventData )
1589   {
1590     if( ! mImpl->IsShowingRealText() )
1591     {
1592       Event event( Event::LONG_PRESS_EVENT );
1593       event.p1.mInt = state;
1594       mImpl->mEventData->mEventQueue.push_back( event );
1595       mImpl->RequestRelayout();
1596     }
1597     else
1598     {
1599       // The 1st long-press on inactive text-field is treated as tap
1600       if( EventData::INACTIVE == mImpl->mEventData->mState )
1601       {
1602         mImpl->ChangeState( EventData::EDITING );
1603
1604         Event event( Event::TAP_EVENT );
1605         event.p1.mUint = 1;
1606         event.p2.mFloat = x;
1607         event.p3.mFloat = y;
1608         mImpl->mEventData->mEventQueue.push_back( event );
1609
1610         mImpl->RequestRelayout();
1611       }
1612       else
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     if ( mImpl->mEventData->mState == EventData::SELECTING )
1625     {
1626       mImpl->ChangeState( EventData::SELECTION_CHANGED );
1627     }
1628     else
1629     {
1630       mImpl->ChangeState( EventData::SELECTING );
1631     }
1632
1633     if( selectAll )
1634     {
1635       Event event( Event::SELECT_ALL );
1636       mImpl->mEventData->mEventQueue.push_back( event );
1637     }
1638     else
1639     {
1640       Event event( Event::SELECT );
1641       event.p2.mFloat = x;
1642       event.p3.mFloat = y;
1643       mImpl->mEventData->mEventQueue.push_back( event );
1644     }
1645
1646     mImpl->RequestRelayout();
1647   }
1648 }
1649
1650 void Controller::GetTargetSize( Vector2& targetSize )
1651 {
1652   targetSize = mImpl->mVisualModel->mControlSize;
1653 }
1654
1655 void Controller::AddDecoration( Actor& actor, bool needsClipping )
1656 {
1657   mImpl->mControlInterface.AddDecoration( actor, needsClipping );
1658 }
1659
1660 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
1661 {
1662   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
1663
1664   if( mImpl->mEventData )
1665   {
1666     switch( handleType )
1667     {
1668       case GRAB_HANDLE:
1669       {
1670         Event event( Event::GRAB_HANDLE_EVENT );
1671         event.p1.mUint  = state;
1672         event.p2.mFloat = x;
1673         event.p3.mFloat = y;
1674
1675         mImpl->mEventData->mEventQueue.push_back( event );
1676         break;
1677       }
1678       case LEFT_SELECTION_HANDLE:
1679       {
1680         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
1681         event.p1.mUint  = state;
1682         event.p2.mFloat = x;
1683         event.p3.mFloat = y;
1684
1685         mImpl->mEventData->mEventQueue.push_back( event );
1686         break;
1687       }
1688       case RIGHT_SELECTION_HANDLE:
1689       {
1690         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
1691         event.p1.mUint  = state;
1692         event.p2.mFloat = x;
1693         event.p3.mFloat = y;
1694
1695         mImpl->mEventData->mEventQueue.push_back( event );
1696         break;
1697       }
1698       case LEFT_SELECTION_HANDLE_MARKER:
1699       case RIGHT_SELECTION_HANDLE_MARKER:
1700       {
1701         // Markers do not move the handles.
1702         break;
1703       }
1704       case HANDLE_TYPE_COUNT:
1705       {
1706         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
1707       }
1708     }
1709
1710     mImpl->RequestRelayout();
1711   }
1712 }
1713
1714 void Controller::PasteText( const std::string& stringToPaste )
1715 {
1716   InsertText( stringToPaste, Text::Controller::COMMIT );
1717   mImpl->ChangeState( EventData::EDITING );
1718   mImpl->RequestRelayout();
1719 }
1720
1721 void Controller::PasteClipboardItemEvent()
1722 {
1723   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
1724   std::string stringToPaste( notifier.GetContent() );
1725   PasteText( stringToPaste );
1726 }
1727
1728 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
1729 {
1730   if( NULL == mImpl->mEventData )
1731   {
1732     return;
1733   }
1734
1735   switch( button )
1736   {
1737     case Toolkit::TextSelectionPopup::CUT:
1738     {
1739       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
1740       mImpl->mOperationsPending = ALL_OPERATIONS;
1741
1742       // This is to reset the virtual keyboard to Upper-case
1743       if( 0u == mImpl->mLogicalModel->mText.Count() )
1744       {
1745         NotifyImfManager();
1746       }
1747
1748       if( 0u != mImpl->mLogicalModel->mText.Count() ||
1749           !mImpl->IsPlaceholderAvailable() )
1750       {
1751         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1752       }
1753       else
1754       {
1755         ShowPlaceholderText();
1756         mImpl->mEventData->mUpdateCursorPosition = true;
1757       }
1758       mImpl->RequestRelayout();
1759       mImpl->mControlInterface.TextChanged();
1760       break;
1761     }
1762     case Toolkit::TextSelectionPopup::COPY:
1763     {
1764       mImpl->SendSelectionToClipboard( false ); // Text not modified
1765       mImpl->RequestRelayout(); // Handles, Selection Highlight, Popup
1766       break;
1767     }
1768     case Toolkit::TextSelectionPopup::PASTE:
1769     {
1770       std::string stringToPaste("");
1771       mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
1772       PasteText( stringToPaste );
1773       break;
1774     }
1775     case Toolkit::TextSelectionPopup::SELECT:
1776     {
1777       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
1778
1779       if( mImpl->mEventData->mSelectionEnabled  )
1780       {
1781         // Creates a SELECT event.
1782         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
1783       }
1784       break;
1785     }
1786     case Toolkit::TextSelectionPopup::SELECT_ALL:
1787     {
1788       // Creates a SELECT_ALL event
1789       SelectEvent( 0.f, 0.f, true );
1790       break;
1791     }
1792     case Toolkit::TextSelectionPopup::CLIPBOARD:
1793     {
1794       mImpl->ShowClipboard();
1795       break;
1796     }
1797     case Toolkit::TextSelectionPopup::NONE:
1798     {
1799       // Nothing to do.
1800       break;
1801     }
1802   }
1803 }
1804
1805 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
1806 {
1807   bool update( false );
1808   bool requestRelayout = false;
1809
1810   std::string text;
1811   unsigned int cursorPosition( 0 );
1812
1813   switch ( imfEvent.eventName )
1814   {
1815     case ImfManager::COMMIT:
1816     {
1817       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
1818       requestRelayout = true;
1819       break;
1820     }
1821     case ImfManager::PREEDIT:
1822     {
1823       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
1824       update = true;
1825       requestRelayout = true;
1826       break;
1827     }
1828     case ImfManager::DELETESURROUNDING:
1829     {
1830       update = RemoveText( imfEvent.cursorOffset, imfEvent.numberOfChars );
1831
1832       if( update )
1833       {
1834         if( 0u != mImpl->mLogicalModel->mText.Count() ||
1835             !mImpl->IsPlaceholderAvailable() )
1836         {
1837           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1838         }
1839         else
1840         {
1841           ShowPlaceholderText();
1842           mImpl->mEventData->mUpdateCursorPosition = true;
1843         }
1844       }
1845       requestRelayout = true;
1846       break;
1847     }
1848     case ImfManager::GETSURROUNDING:
1849     {
1850       GetText( text );
1851       cursorPosition = GetLogicalCursorPosition();
1852
1853       imfManager.SetSurroundingText( text );
1854       imfManager.SetCursorPosition( cursorPosition );
1855       break;
1856     }
1857     case ImfManager::VOID:
1858     {
1859       // do nothing
1860       break;
1861     }
1862   } // end switch
1863
1864   if( ImfManager::GETSURROUNDING != imfEvent.eventName )
1865   {
1866     GetText( text );
1867     cursorPosition = GetLogicalCursorPosition();
1868   }
1869
1870   if( requestRelayout )
1871   {
1872     mImpl->mOperationsPending = ALL_OPERATIONS;
1873     mImpl->RequestRelayout();
1874
1875     // Do this last since it provides callbacks into application code
1876     mImpl->mControlInterface.TextChanged();
1877   }
1878
1879   ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
1880
1881   return callbackData;
1882 }
1883
1884 Controller::~Controller()
1885 {
1886   delete mImpl;
1887 }
1888
1889 bool Controller::BackspaceKeyEvent()
1890 {
1891   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
1892
1893   // IMF manager is no longer handling key-events
1894   mImpl->ClearPreEditFlag();
1895
1896   bool removed( false );
1897
1898   if ( EventData::SELECTING         == mImpl->mEventData->mState ||
1899        EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
1900   {
1901     removed = RemoveSelectedText();
1902   }
1903   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
1904   {
1905     // Remove the character before the current cursor position
1906     removed = RemoveText( -1, 1 );
1907   }
1908
1909   if( removed )
1910   {
1911     // This is to reset the virtual keyboard to Upper-case
1912     if( 0u == mImpl->mLogicalModel->mText.Count() )
1913     {
1914       NotifyImfManager();
1915     }
1916
1917     if( 0u != mImpl->mLogicalModel->mText.Count() ||
1918         !mImpl->IsPlaceholderAvailable() )
1919     {
1920       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1921     }
1922     else
1923     {
1924       ShowPlaceholderText();
1925       mImpl->mEventData->mUpdateCursorPosition = true;
1926     }
1927   }
1928
1929   return removed;
1930 }
1931
1932 void Controller::NotifyImfManager()
1933 {
1934   if( mImpl->mEventData )
1935   {
1936     ImfManager imfManager = ImfManager::Get();
1937
1938     if( imfManager )
1939     {
1940       // Notifying IMF of a cursor change triggers a surrounding text request so updating it now.
1941       std::string text;
1942       GetText( text );
1943       imfManager.SetSurroundingText( text );
1944
1945       imfManager.SetCursorPosition( GetLogicalCursorPosition() );
1946       imfManager.NotifyCursorPosition();
1947     }
1948   }
1949 }
1950
1951 void Controller::ShowPlaceholderText()
1952 {
1953   if( mImpl->IsPlaceholderAvailable() )
1954   {
1955     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
1956
1957     mImpl->mEventData->mIsShowingPlaceholderText = true;
1958
1959     // Disable handles when showing place-holder text
1960     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1961     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1962     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1963
1964     const char* text( NULL );
1965     size_t size( 0 );
1966
1967     // TODO - Switch placeholder text styles when changing state
1968     if( EventData::INACTIVE != mImpl->mEventData->mState &&
1969         0u != mImpl->mEventData->mPlaceholderTextActive.c_str() )
1970     {
1971       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
1972       size = mImpl->mEventData->mPlaceholderTextActive.size();
1973     }
1974     else
1975     {
1976       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
1977       size = mImpl->mEventData->mPlaceholderTextInactive.size();
1978     }
1979
1980     // Reset model for showing placeholder.
1981     mImpl->mLogicalModel->mText.Clear();
1982     ClearModelData();
1983     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
1984
1985     // Convert text into UTF-32
1986     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1987     utf32Characters.Resize( size );
1988
1989     // This is a bit horrible but std::string returns a (signed) char*
1990     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
1991
1992     // Transform a text array encoded in utf8 into an array encoded in utf32.
1993     // It returns the actual number of characters.
1994     Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
1995     utf32Characters.Resize( characterCount );
1996
1997     // Reset the cursor position
1998     mImpl->mEventData->mPrimaryCursorPosition = 0;
1999
2000     // The natural size needs to be re-calculated.
2001     mImpl->mRecalculateNaturalSize = true;
2002
2003     // Apply modifications to the model
2004     mImpl->mOperationsPending = ALL_OPERATIONS;
2005
2006     // Update the rest of the model during size negotiation
2007     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
2008   }
2009 }
2010
2011 void Controller::ClearModelData()
2012 {
2013   // n.b. This does not Clear the mText from mLogicalModel
2014   mImpl->mLogicalModel->mScriptRuns.Clear();
2015   mImpl->mLogicalModel->mFontRuns.Clear();
2016   mImpl->mLogicalModel->mLineBreakInfo.Clear();
2017   mImpl->mLogicalModel->mWordBreakInfo.Clear();
2018   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
2019   mImpl->mLogicalModel->mCharacterDirections.Clear();
2020   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
2021   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
2022   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
2023   mImpl->mVisualModel->mGlyphs.Clear();
2024   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
2025   mImpl->mVisualModel->mCharactersToGlyph.Clear();
2026   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
2027   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
2028   mImpl->mVisualModel->mGlyphPositions.Clear();
2029   mImpl->mVisualModel->mLines.Clear();
2030   mImpl->mVisualModel->ClearCaches();
2031 }
2032
2033 void Controller::ClearFontData()
2034 {
2035   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
2036   mImpl->mLogicalModel->mFontRuns.Clear();
2037   mImpl->mVisualModel->mGlyphs.Clear();
2038   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
2039   mImpl->mVisualModel->mCharactersToGlyph.Clear();
2040   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
2041   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
2042   mImpl->mVisualModel->mGlyphPositions.Clear();
2043   mImpl->mVisualModel->mLines.Clear();
2044   mImpl->mVisualModel->ClearCaches();
2045 }
2046
2047 Controller::Controller( ControlInterface& controlInterface )
2048 : mImpl( NULL )
2049 {
2050   mImpl = new Controller::Impl( controlInterface );
2051 }
2052
2053 } // namespace Text
2054
2055 } // namespace Toolkit
2056
2057 } // namespace Dali