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