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