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