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