TextController - Update the text model.
[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 <memory.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/internal/text/bidirectional-support.h>
30 #include <dali-toolkit/internal/text/character-set-conversion.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/markup-processor.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34
35 namespace
36 {
37
38 #if defined(DEBUG_ENABLED)
39   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
40 #endif
41
42 const float MAX_FLOAT = std::numeric_limits<float>::max();
43 const unsigned int POINTS_PER_INCH = 72;
44
45 const std::string EMPTY_STRING("");
46
47 float ConvertToEven( float value )
48 {
49   int intValue(static_cast<int>( value ));
50   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
51 }
52
53 } // namespace
54
55 namespace Dali
56 {
57
58 namespace Toolkit
59 {
60
61 namespace Text
62 {
63
64 /**
65  * @brief Adds a new font description run for the selected text.
66  *
67  * The new font parameters are added after the call to this method.
68  *
69  * @param[in] eventData The event data pointer.
70  * @param[in] logicalModel The logical model where to add the new font description run.
71  */
72 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
73                                                  LogicalModelPtr logicalModel )
74 {
75   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
76
77   // Get start and end position of selection
78   const CharacterIndex startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
79   const Length lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
80
81   // Add the font run.
82   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
83   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
84
85   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
86
87   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
88   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
89
90   // Recalculate the selection highlight as the metrics may have changed.
91   eventData->mUpdateLeftSelectionPosition = true;
92   eventData->mUpdateRightSelectionPosition = true;
93
94   return fontDescriptionRun;
95 }
96
97 ControllerPtr Controller::New( ControlInterface& controlInterface )
98 {
99   return ControllerPtr( new Controller( controlInterface ) );
100 }
101
102 void Controller::EnableTextInput( DecoratorPtr decorator )
103 {
104   if( NULL == mImpl->mEventData )
105   {
106     mImpl->mEventData = new EventData( decorator );
107   }
108 }
109
110 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
111 {
112   // Metrics for bitmap & vector based glyphs are different
113   mImpl->mMetrics->SetGlyphType( glyphType );
114
115   // Clear the font-specific data
116   ClearFontData();
117
118   mImpl->mOperationsPending = ALL_OPERATIONS;
119   mImpl->mRecalculateNaturalSize = true;
120
121   mImpl->RequestRelayout();
122 }
123
124 void Controller::SetMarkupProcessorEnabled( bool enable )
125 {
126   mImpl->mMarkupProcessorEnabled = enable;
127 }
128
129 bool Controller::IsMarkupProcessorEnabled() const
130 {
131   return mImpl->mMarkupProcessorEnabled;
132 }
133
134 void Controller::SetText( const std::string& text )
135 {
136   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
137
138   // Reset keyboard as text changed
139   mImpl->ResetImfManager();
140
141   // Remove the previously set text and style.
142   ResetText();
143
144   // Remove the style.
145   ClearStyleData();
146
147   CharacterIndex lastCursorIndex = 0u;
148
149   if( NULL != mImpl->mEventData )
150   {
151     // If popup shown then hide it by switching to Editing state
152     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
153         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
154         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
155         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
156     {
157       mImpl->ChangeState( EventData::EDITING );
158     }
159   }
160
161   if( !text.empty() )
162   {
163     MarkupProcessData markupProcessData( mImpl->mLogicalModel->mColorRuns,
164                                          mImpl->mLogicalModel->mFontDescriptionRuns );
165
166     Length textSize = 0u;
167     const uint8_t* utf8 = NULL;
168     if( mImpl->mMarkupProcessorEnabled )
169     {
170       ProcessMarkupString( text, markupProcessData );
171       textSize = markupProcessData.markupProcessedText.size();
172
173       // This is a bit horrible but std::string returns a (signed) char*
174       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
175     }
176     else
177     {
178       textSize = text.size();
179
180       // This is a bit horrible but std::string returns a (signed) char*
181       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
182     }
183
184     //  Convert text into UTF-32
185     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
186     utf32Characters.Resize( textSize );
187
188     // Transform a text array encoded in utf8 into an array encoded in utf32.
189     // It returns the actual number of characters.
190     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
191     utf32Characters.Resize( characterCount );
192
193     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
194     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mLogicalModel->mText.Count() );
195
196     // The characters to be added.
197     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
198
199     // To reset the cursor position
200     lastCursorIndex = characterCount;
201
202     // Update the rest of the model during size negotiation
203     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
204
205     // The natural size needs to be re-calculated.
206     mImpl->mRecalculateNaturalSize = true;
207
208     // Apply modifications to the model
209     mImpl->mOperationsPending = ALL_OPERATIONS;
210   }
211   else
212   {
213     ShowPlaceholderText();
214   }
215
216   // Resets the cursor position.
217   ResetCursorPosition( lastCursorIndex );
218
219   // Scrolls the text to make the cursor visible.
220   ResetScrollPosition();
221
222   mImpl->RequestRelayout();
223
224   if( NULL != mImpl->mEventData )
225   {
226     // Cancel previously queued events
227     mImpl->mEventData->mEventQueue.clear();
228   }
229
230   // Notify IMF as text changed
231   NotifyImfManager();
232
233   // Do this last since it provides callbacks into application code
234   mImpl->mControlInterface.TextChanged();
235 }
236
237 void Controller::GetText( std::string& text ) const
238 {
239   if( !mImpl->IsShowingPlaceholderText() )
240   {
241     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
242
243     if( 0u != utf32Characters.Count() )
244     {
245       Utf32ToUtf8( &utf32Characters[0], utf32Characters.Count(), text );
246     }
247   }
248   else
249   {
250     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
251   }
252 }
253
254 unsigned int Controller::GetLogicalCursorPosition() const
255 {
256   if( NULL != mImpl->mEventData )
257   {
258     return mImpl->mEventData->mPrimaryCursorPosition;
259   }
260
261   return 0u;
262 }
263
264 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
265 {
266   if( NULL != mImpl->mEventData )
267   {
268     if( PLACEHOLDER_TYPE_INACTIVE == type )
269     {
270       mImpl->mEventData->mPlaceholderTextInactive = text;
271     }
272     else
273     {
274       mImpl->mEventData->mPlaceholderTextActive = text;
275     }
276
277     // Update placeholder if there is no text
278     if( mImpl->IsShowingPlaceholderText() ||
279         ( 0u == mImpl->mLogicalModel->mText.Count() ) )
280     {
281       ShowPlaceholderText();
282     }
283   }
284 }
285
286 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
287 {
288   if( NULL != mImpl->mEventData )
289   {
290     if( PLACEHOLDER_TYPE_INACTIVE == type )
291     {
292       text = mImpl->mEventData->mPlaceholderTextInactive;
293     }
294     else
295     {
296       text = mImpl->mEventData->mPlaceholderTextActive;
297     }
298   }
299 }
300
301 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
302 {
303   mImpl->mMaximumNumberOfCharacters = maxCharacters;
304 }
305
306 int Controller::GetMaximumNumberOfCharacters()
307 {
308   return mImpl->mMaximumNumberOfCharacters;
309 }
310
311 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
312 {
313   if( NULL == mImpl->mFontDefaults )
314   {
315     mImpl->mFontDefaults = new FontDefaults();
316   }
317
318   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
319   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
320   mImpl->mFontDefaults->familyDefined = true;
321
322   // Clear the font-specific data
323   ClearFontData();
324
325   mImpl->mOperationsPending = ALL_OPERATIONS;
326   mImpl->mRecalculateNaturalSize = true;
327
328   mImpl->RequestRelayout();
329 }
330
331 const std::string& Controller::GetDefaultFontFamily() const
332 {
333   if( NULL != mImpl->mFontDefaults )
334   {
335     return mImpl->mFontDefaults->mFontDescription.family;
336   }
337
338   return EMPTY_STRING;
339 }
340
341 void Controller::SetDefaultFontStyle( const std::string& style )
342 {
343   if( NULL == mImpl->mFontDefaults )
344   {
345     mImpl->mFontDefaults = new FontDefaults();
346   }
347
348   mImpl->mFontDefaults->mFontStyle = style;
349 }
350
351 const std::string& Controller::GetDefaultFontStyle() const
352 {
353   if( NULL != mImpl->mFontDefaults )
354   {
355     return mImpl->mFontDefaults->mFontStyle;
356   }
357
358   return EMPTY_STRING;
359 }
360
361 void Controller::SetDefaultFontWeight( FontWeight weight )
362 {
363   if( NULL == mImpl->mFontDefaults )
364   {
365     mImpl->mFontDefaults = new FontDefaults();
366   }
367
368   mImpl->mFontDefaults->mFontDescription.weight = weight;
369   mImpl->mFontDefaults->weightDefined = true;
370
371   // Clear the font-specific data
372   ClearFontData();
373
374   mImpl->mOperationsPending = ALL_OPERATIONS;
375   mImpl->mRecalculateNaturalSize = true;
376
377   mImpl->RequestRelayout();
378 }
379
380 FontWeight Controller::GetDefaultFontWeight() const
381 {
382   if( NULL != mImpl->mFontDefaults )
383   {
384     return mImpl->mFontDefaults->mFontDescription.weight;
385   }
386
387   return TextAbstraction::FontWeight::NORMAL;
388 }
389
390 void Controller::SetDefaultFontWidth( FontWidth width )
391 {
392   if( NULL == mImpl->mFontDefaults )
393   {
394     mImpl->mFontDefaults = new FontDefaults();
395   }
396
397   mImpl->mFontDefaults->mFontDescription.width = width;
398   mImpl->mFontDefaults->widthDefined = true;
399
400   // Clear the font-specific data
401   ClearFontData();
402
403   mImpl->mOperationsPending = ALL_OPERATIONS;
404   mImpl->mRecalculateNaturalSize = true;
405
406   mImpl->RequestRelayout();
407 }
408
409 FontWidth Controller::GetDefaultFontWidth() const
410 {
411   if( NULL != mImpl->mFontDefaults )
412   {
413     return mImpl->mFontDefaults->mFontDescription.width;
414   }
415
416   return TextAbstraction::FontWidth::NORMAL;
417 }
418
419 void Controller::SetDefaultFontSlant( FontSlant slant )
420 {
421   if( NULL == mImpl->mFontDefaults )
422   {
423     mImpl->mFontDefaults = new FontDefaults();
424   }
425
426   mImpl->mFontDefaults->mFontDescription.slant = slant;
427   mImpl->mFontDefaults->slantDefined = true;
428
429   // Clear the font-specific data
430   ClearFontData();
431
432   mImpl->mOperationsPending = ALL_OPERATIONS;
433   mImpl->mRecalculateNaturalSize = true;
434
435   mImpl->RequestRelayout();
436 }
437
438 FontSlant Controller::GetDefaultFontSlant() const
439 {
440   if( NULL != mImpl->mFontDefaults )
441   {
442     return mImpl->mFontDefaults->mFontDescription.slant;
443   }
444
445   return TextAbstraction::FontSlant::NORMAL;
446 }
447
448 void Controller::SetDefaultPointSize( float pointSize )
449 {
450   if( NULL == mImpl->mFontDefaults )
451   {
452     mImpl->mFontDefaults = new FontDefaults();
453   }
454
455   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
456   mImpl->mFontDefaults->sizeDefined = true;
457
458   unsigned int horizontalDpi( 0u );
459   unsigned int verticalDpi( 0u );
460   mImpl->mFontClient.GetDpi( horizontalDpi, verticalDpi );
461
462   // Adjust the metrics if the fixed-size font should be down-scaled
463   int maxEmojiSize( pointSize/POINTS_PER_INCH * verticalDpi );
464   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultPointSize %p setting MaxEmojiSize %d\n", this, maxEmojiSize );
465   mImpl->mMetrics->SetMaxEmojiSize( maxEmojiSize );
466
467   // Clear the font-specific data
468   ClearFontData();
469
470   mImpl->mOperationsPending = ALL_OPERATIONS;
471   mImpl->mRecalculateNaturalSize = true;
472
473   mImpl->RequestRelayout();
474 }
475
476 float Controller::GetDefaultPointSize() const
477 {
478   if( NULL != mImpl->mFontDefaults )
479   {
480     return mImpl->mFontDefaults->mDefaultPointSize;
481   }
482
483   return 0.0f;
484 }
485
486 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
487 {
488   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange");
489
490   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
491   {
492     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
493     ClearFontData();
494     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
495     mImpl->UpdateModel( ALL_OPERATIONS );
496     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
497     mImpl->mRecalculateNaturalSize = true;
498     mImpl->RequestRelayout();
499   }
500 }
501
502 void Controller::SetTextColor( const Vector4& textColor )
503 {
504   mImpl->mTextColor = textColor;
505
506   if( !mImpl->IsShowingPlaceholderText() )
507   {
508     mImpl->mVisualModel->SetTextColor( textColor );
509
510     mImpl->RequestRelayout();
511   }
512 }
513
514 const Vector4& Controller::GetTextColor() const
515 {
516   return mImpl->mTextColor;
517 }
518
519 bool Controller::RemoveText( int cursorOffset, int numberOfCharacters )
520 {
521   bool removed = false;
522
523   if( NULL == mImpl->mEventData )
524   {
525     return removed;
526   }
527
528   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
529                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
530
531   if( !mImpl->IsShowingPlaceholderText() )
532   {
533     // Delete at current cursor position
534     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
535     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
536
537     CharacterIndex cursorIndex = oldCursorIndex;
538
539     // Validate the cursor position & number of characters
540     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
541     {
542       cursorIndex = oldCursorIndex + cursorOffset;
543     }
544
545     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
546     {
547       numberOfCharacters = currentText.Count() - cursorIndex;
548     }
549
550     if( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
551     {
552       // Mark the paragraphs to be updated.
553       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
554       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
555
556       // Update the input style and remove the text's style before removing the text.
557
558       // Set first the default input style.
559       mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
560
561       // Update the input style.
562       mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
563
564       // Remove the text's style before removing the text.
565       mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
566
567       // Remove the characters.
568       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
569       Vector<Character>::Iterator last  = first + numberOfCharacters;
570
571       currentText.Erase( first, last );
572
573       // Cursor position retreat
574       oldCursorIndex = cursorIndex;
575
576       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
577       removed = true;
578     }
579   }
580
581   return removed;
582 }
583
584 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
585 {
586   if( NULL != mImpl->mEventData )
587   {
588     mImpl->mEventData->mPlaceholderTextColor = textColor;
589   }
590
591   if( mImpl->IsShowingPlaceholderText() )
592   {
593     mImpl->mVisualModel->SetTextColor( textColor );
594     mImpl->RequestRelayout();
595   }
596 }
597
598 const Vector4& Controller::GetPlaceholderTextColor() const
599 {
600   if( NULL != mImpl->mEventData )
601   {
602     return mImpl->mEventData->mPlaceholderTextColor;
603   }
604
605   return Color::BLACK;
606 }
607
608 void Controller::SetShadowOffset( const Vector2& shadowOffset )
609 {
610   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
611
612   mImpl->RequestRelayout();
613 }
614
615 const Vector2& Controller::GetShadowOffset() const
616 {
617   return mImpl->mVisualModel->GetShadowOffset();
618 }
619
620 void Controller::SetShadowColor( const Vector4& shadowColor )
621 {
622   mImpl->mVisualModel->SetShadowColor( shadowColor );
623
624   mImpl->RequestRelayout();
625 }
626
627 const Vector4& Controller::GetShadowColor() const
628 {
629   return mImpl->mVisualModel->GetShadowColor();
630 }
631
632 void Controller::SetUnderlineColor( const Vector4& color )
633 {
634   mImpl->mVisualModel->SetUnderlineColor( color );
635
636   mImpl->RequestRelayout();
637 }
638
639 const Vector4& Controller::GetUnderlineColor() const
640 {
641   return mImpl->mVisualModel->GetUnderlineColor();
642 }
643
644 void Controller::SetUnderlineEnabled( bool enabled )
645 {
646   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
647
648   mImpl->RequestRelayout();
649 }
650
651 bool Controller::IsUnderlineEnabled() const
652 {
653   return mImpl->mVisualModel->IsUnderlineEnabled();
654 }
655
656 void Controller::SetUnderlineHeight( float height )
657 {
658   mImpl->mVisualModel->SetUnderlineHeight( height );
659
660   mImpl->RequestRelayout();
661 }
662
663 float Controller::GetUnderlineHeight() const
664 {
665   return mImpl->mVisualModel->GetUnderlineHeight();
666 }
667
668 void Controller::SetInputColor( const Vector4& color )
669 {
670   if( NULL != mImpl->mEventData )
671   {
672     mImpl->mEventData->mInputStyle.textColor = color;
673
674     if( EventData::SELECTING == mImpl->mEventData->mState )
675     {
676       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
677
678       // Get start and end position of selection
679       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
680       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
681
682       // Add the color run.
683       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
684       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
685
686       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
687       colorRun.color = color;
688       colorRun.characterRun.characterIndex = startOfSelectedText;
689       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
690
691       // Request to relayout.
692       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
693       mImpl->RequestRelayout();
694     }
695   }
696 }
697
698 const Vector4& Controller::GetInputColor() const
699 {
700   if( NULL != mImpl->mEventData )
701   {
702     return mImpl->mEventData->mInputStyle.textColor;
703   }
704
705   // Return the default text's color if there is no EventData.
706   return mImpl->mTextColor;
707
708 }
709
710 void Controller::SetInputFontFamily( const std::string& fontFamily )
711 {
712   if( NULL != mImpl->mEventData )
713   {
714     mImpl->mEventData->mInputStyle.familyName = fontFamily;
715     mImpl->mEventData->mInputStyle.familyDefined = true;
716
717     if( EventData::SELECTING == mImpl->mEventData->mState )
718     {
719       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
720                                                                             mImpl->mLogicalModel );
721
722       fontDescriptionRun.familyLength = fontFamily.size();
723       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
724       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
725       fontDescriptionRun.familyDefined = true;
726
727       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
728
729       // Request to relayout.
730       mImpl->mOperationsPending = ALL_OPERATIONS;
731       mImpl->mRecalculateNaturalSize = true;
732       mImpl->RequestRelayout();
733
734       // As the font changes, recalculate the handle positions is needed.
735       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
736       mImpl->mEventData->mUpdateRightSelectionPosition = true;
737       mImpl->mEventData->mScrollAfterUpdatePosition = true;
738     }
739   }
740 }
741
742 const std::string& Controller::GetInputFontFamily() const
743 {
744   if( NULL != mImpl->mEventData )
745   {
746     return mImpl->mEventData->mInputStyle.familyName;
747   }
748
749   // Return the default font's family if there is no EventData.
750   return GetDefaultFontFamily();
751 }
752
753 void Controller::SetInputFontStyle( const std::string& fontStyle )
754 {
755   if( NULL != mImpl->mEventData )
756   {
757     mImpl->mEventData->mInputStyle.fontStyle = fontStyle;
758   }
759 }
760
761 const std::string& Controller::GetInputFontStyle() const
762 {
763   if( NULL != mImpl->mEventData )
764   {
765     return mImpl->mEventData->mInputStyle.fontStyle;
766   }
767
768   // Return the default font's style if there is no EventData.
769   return GetDefaultFontStyle();
770 }
771
772 void Controller::SetInputFontWeight( FontWeight weight )
773 {
774   if( NULL != mImpl->mEventData )
775   {
776     mImpl->mEventData->mInputStyle.weight = weight;
777     mImpl->mEventData->mInputStyle.weightDefined = true;
778
779     if( EventData::SELECTING == mImpl->mEventData->mState )
780     {
781       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
782                                                                             mImpl->mLogicalModel );
783
784       fontDescriptionRun.weight = weight;
785       fontDescriptionRun.weightDefined = true;
786
787       // Request to relayout.
788       mImpl->mOperationsPending = ALL_OPERATIONS;
789       mImpl->mRecalculateNaturalSize = true;
790       mImpl->RequestRelayout();
791
792       // As the font might change, recalculate the handle positions is needed.
793       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
794       mImpl->mEventData->mUpdateRightSelectionPosition = true;
795       mImpl->mEventData->mScrollAfterUpdatePosition = true;
796     }
797   }
798 }
799
800 FontWeight Controller::GetInputFontWeight() const
801 {
802   if( NULL != mImpl->mEventData )
803   {
804     return mImpl->mEventData->mInputStyle.weight;
805   }
806
807   return GetDefaultFontWeight();
808 }
809
810 void Controller::SetInputFontWidth( FontWidth width )
811 {
812   if( NULL != mImpl->mEventData )
813   {
814     mImpl->mEventData->mInputStyle.width = width;
815     mImpl->mEventData->mInputStyle.widthDefined = true;
816
817     if( EventData::SELECTING == mImpl->mEventData->mState )
818     {
819       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
820                                                                             mImpl->mLogicalModel );
821
822       fontDescriptionRun.width = width;
823       fontDescriptionRun.widthDefined = true;
824
825       // Request to relayout.
826       mImpl->mOperationsPending = ALL_OPERATIONS;
827       mImpl->mRecalculateNaturalSize = true;
828       mImpl->RequestRelayout();
829
830       // As the font might change, recalculate the handle positions is needed.
831       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
832       mImpl->mEventData->mUpdateRightSelectionPosition = true;
833       mImpl->mEventData->mScrollAfterUpdatePosition = true;
834     }
835   }
836 }
837
838 FontWidth Controller::GetInputFontWidth() const
839 {
840   if( NULL != mImpl->mEventData )
841   {
842     return mImpl->mEventData->mInputStyle.width;
843   }
844
845   return GetDefaultFontWidth();
846 }
847
848 void Controller::SetInputFontSlant( FontSlant slant )
849 {
850   if( NULL != mImpl->mEventData )
851   {
852     mImpl->mEventData->mInputStyle.slant = slant;
853     mImpl->mEventData->mInputStyle.slantDefined = true;
854
855     if( EventData::SELECTING == mImpl->mEventData->mState )
856     {
857       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
858                                                                             mImpl->mLogicalModel );
859
860       fontDescriptionRun.slant = slant;
861       fontDescriptionRun.slantDefined = true;
862
863       // Request to relayout.
864       mImpl->mOperationsPending = ALL_OPERATIONS;
865       mImpl->mRecalculateNaturalSize = true;
866       mImpl->RequestRelayout();
867
868       // As the font might change, recalculate the handle positions is needed.
869       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
870       mImpl->mEventData->mUpdateRightSelectionPosition = true;
871       mImpl->mEventData->mScrollAfterUpdatePosition = true;
872     }
873   }
874 }
875
876 FontSlant Controller::GetInputFontSlant() const
877 {
878   if( NULL != mImpl->mEventData )
879   {
880     return mImpl->mEventData->mInputStyle.slant;
881   }
882
883   return GetDefaultFontSlant();
884 }
885
886 void Controller::SetInputFontPointSize( float size )
887 {
888   if( NULL != mImpl->mEventData )
889   {
890     mImpl->mEventData->mInputStyle.size = size;
891
892     if( EventData::SELECTING == mImpl->mEventData->mState )
893     {
894       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
895                                                                             mImpl->mLogicalModel );
896
897       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
898       fontDescriptionRun.sizeDefined = true;
899
900       // Request to relayout.
901       mImpl->mOperationsPending = ALL_OPERATIONS;
902       mImpl->mRecalculateNaturalSize = true;
903       mImpl->RequestRelayout();
904
905       // As the font might change, recalculate the handle positions is needed.
906       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
907       mImpl->mEventData->mUpdateRightSelectionPosition = true;
908       mImpl->mEventData->mScrollAfterUpdatePosition = true;
909     }
910   }
911 }
912
913 float Controller::GetInputFontPointSize() const
914 {
915   if( NULL != mImpl->mEventData )
916   {
917     return mImpl->mEventData->mInputStyle.size;
918   }
919
920   // Return the default font's point size if there is no EventData.
921   return GetDefaultPointSize();
922 }
923
924 void Controller::SetEnableCursorBlink( bool enable )
925 {
926   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
927
928   if( NULL != mImpl->mEventData )
929   {
930     mImpl->mEventData->mCursorBlinkEnabled = enable;
931
932     if( !enable &&
933         mImpl->mEventData->mDecorator )
934     {
935       mImpl->mEventData->mDecorator->StopCursorBlink();
936     }
937   }
938 }
939
940 bool Controller::GetEnableCursorBlink() const
941 {
942   if( NULL != mImpl->mEventData )
943   {
944     return mImpl->mEventData->mCursorBlinkEnabled;
945   }
946
947   return false;
948 }
949
950 const Vector2& Controller::GetScrollPosition() const
951 {
952   if( NULL != mImpl->mEventData )
953   {
954     return mImpl->mEventData->mScrollPosition;
955   }
956
957   return Vector2::ZERO;
958 }
959
960 const Vector2& Controller::GetAlignmentOffset() const
961 {
962   return mImpl->mAlignmentOffset;
963 }
964
965 Vector3 Controller::GetNaturalSize()
966 {
967   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
968   Vector3 naturalSize;
969
970   // Make sure the model is up-to-date before layouting
971   ProcessModifyEvents();
972
973   if( mImpl->mRecalculateNaturalSize )
974   {
975     // Operations that can be done only once until the text changes.
976     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
977                                                                            GET_SCRIPTS       |
978                                                                            VALIDATE_FONTS    |
979                                                                            GET_LINE_BREAKS   |
980                                                                            GET_WORD_BREAKS   |
981                                                                            BIDI_INFO         |
982                                                                            SHAPE_TEXT        |
983                                                                            GET_GLYPH_METRICS );
984     // Make sure the model is up-to-date before layouting
985     mImpl->UpdateModel( onlyOnceOperations );
986
987     // Layout the text for the new width.
988     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
989
990     // Set the update info to relayout the whole text.
991     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
992     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
993
994     // Store the actual control's width.
995     const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
996
997     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
998                 static_cast<OperationsMask>( onlyOnceOperations |
999                                              LAYOUT ),
1000                 naturalSize.GetVectorXY() );
1001
1002     // Do not do again the only once operations.
1003     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1004
1005     // Do the size related operations again.
1006     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1007                                                                         ALIGN  |
1008                                                                         REORDER );
1009     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1010
1011     // Stores the natural size to avoid recalculate it again
1012     // unless the text/style changes.
1013     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1014
1015     mImpl->mRecalculateNaturalSize = false;
1016
1017     // Clear the update info. This info will be set the next time the text is updated.
1018     mImpl->mTextUpdateInfo.Clear();
1019
1020     // Restore the actual control's width.
1021     mImpl->mVisualModel->mControlSize.width = actualControlWidth;
1022
1023     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1024   }
1025   else
1026   {
1027     naturalSize = mImpl->mVisualModel->GetNaturalSize();
1028
1029     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1030   }
1031
1032   naturalSize.x = ConvertToEven( naturalSize.x );
1033   naturalSize.y = ConvertToEven( naturalSize.y );
1034
1035   return naturalSize;
1036 }
1037
1038 float Controller::GetHeightForWidth( float width )
1039 {
1040   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1041   // Make sure the model is up-to-date before layouting
1042   ProcessModifyEvents();
1043
1044   Size layoutSize;
1045   if( fabsf( width - mImpl->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 )
1046   {
1047     // Operations that can be done only once until the text changes.
1048     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1049                                                                            GET_SCRIPTS       |
1050                                                                            VALIDATE_FONTS    |
1051                                                                            GET_LINE_BREAKS   |
1052                                                                            GET_WORD_BREAKS   |
1053                                                                            BIDI_INFO         |
1054                                                                            SHAPE_TEXT        |
1055                                                                            GET_GLYPH_METRICS );
1056     // Make sure the model is up-to-date before layouting
1057     mImpl->UpdateModel( onlyOnceOperations );
1058
1059
1060     // Layout the text for the new width.
1061     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1062
1063     // Set the update info to relayout the whole text.
1064     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1065     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
1066
1067     // Store the actual control's width.
1068     const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
1069
1070     DoRelayout( Size( width, MAX_FLOAT ),
1071                 static_cast<OperationsMask>( onlyOnceOperations |
1072                                              LAYOUT ),
1073                 layoutSize );
1074
1075     // Do not do again the only once operations.
1076     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1077
1078     // Do the size related operations again.
1079     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1080                                                                         ALIGN  |
1081                                                                         REORDER );
1082
1083     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1084
1085     // Clear the update info. This info will be set the next time the text is updated.
1086     mImpl->mTextUpdateInfo.Clear();
1087
1088     // Restore the actual control's width.
1089     mImpl->mVisualModel->mControlSize.width = actualControlWidth;
1090
1091     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1092   }
1093   else
1094   {
1095     layoutSize = mImpl->mVisualModel->GetLayoutSize();
1096     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1097   }
1098
1099   return layoutSize.height;
1100 }
1101
1102 bool Controller::Relayout( const Size& size )
1103 {
1104   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f\n", this, size.width, size.height );
1105
1106   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1107   {
1108     bool glyphsRemoved( false );
1109     if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
1110     {
1111       mImpl->mVisualModel->mGlyphPositions.Clear();
1112       glyphsRemoved = true;
1113     }
1114
1115     // Clear the update info. This info will be set the next time the text is updated.
1116     mImpl->mTextUpdateInfo.Clear();
1117
1118     // Not worth to relayout if width or height is equal to zero.
1119     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
1120     return glyphsRemoved;
1121   }
1122
1123   // Whether a new size has been set.
1124   const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
1125
1126   if( newSize )
1127   {
1128     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
1129
1130     // Layout operations that need to be done if the size changes.
1131     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1132                                                              LAYOUT                    |
1133                                                              ALIGN                     |
1134                                                              UPDATE_ACTUAL_SIZE        |
1135                                                              REORDER );
1136     // Set the update info to relayout the whole text.
1137     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1138     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1139   }
1140
1141   // Whether there are modify events.
1142   const bool isModifyEventsEmpty = 0u == mImpl->mModifyEvents.Count();
1143
1144   // Make sure the model is up-to-date before layouting.
1145   ProcessModifyEvents();
1146   mImpl->UpdateModel( mImpl->mOperationsPending );
1147
1148   // Style operations that need to be done if the text is modified.
1149   if( !isModifyEventsEmpty )
1150   {
1151     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1152                                                              COLOR );
1153   }
1154
1155   // Apply the style runs if text is modified.
1156   bool updated = mImpl->UpdateModelStyle( mImpl->mOperationsPending );
1157
1158   // Layout the text.
1159   Size layoutSize;
1160   updated = DoRelayout( size,
1161                         mImpl->mOperationsPending,
1162                         layoutSize ) || updated;
1163
1164   // Do not re-do any operation until something changes.
1165   mImpl->mOperationsPending = NO_OPERATION;
1166
1167   // Whether the text control is editable
1168   const bool isEditable = NULL != mImpl->mEventData;
1169
1170   // Keep the current offset and alignment as it will be used to update the decorator's positions (if the size changes).
1171   Vector2 offset;
1172   if( newSize && isEditable )
1173   {
1174     offset = mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition;
1175   }
1176
1177   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
1178   CalculateTextAlignment( size );
1179
1180   if( isEditable )
1181   {
1182     if( newSize )
1183     {
1184       // If there is a new size, the scroll position needs to be clamped.
1185       mImpl->ClampHorizontalScroll( layoutSize );
1186
1187       // Update the decorator's positions is needed if there is a new size.
1188       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
1189     }
1190
1191     // Move the cursor, grab handle etc.
1192     updated = mImpl->ProcessInputEvents() || updated;
1193   }
1194
1195   // Clear the update info. This info will be set the next time the text is updated.
1196   mImpl->mTextUpdateInfo.Clear();
1197
1198   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
1199   return updated;
1200 }
1201
1202 void Controller::ProcessModifyEvents()
1203 {
1204   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
1205
1206   if( 0u == events.Count() )
1207   {
1208     // Nothing to do.
1209     return;
1210   }
1211
1212   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
1213          endIt = events.End();
1214        it != endIt;
1215        ++it )
1216   {
1217     const ModifyEvent& event = *it;
1218
1219     if( ModifyEvent::TEXT_REPLACED == event.type )
1220     {
1221       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
1222       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
1223
1224       TextReplacedEvent();
1225     }
1226     else if( ModifyEvent::TEXT_INSERTED == event.type )
1227     {
1228       TextInsertedEvent();
1229     }
1230     else if( ModifyEvent::TEXT_DELETED == event.type )
1231     {
1232       // Placeholder-text cannot be deleted
1233       if( !mImpl->IsShowingPlaceholderText() )
1234       {
1235         TextDeletedEvent();
1236       }
1237     }
1238   }
1239
1240   if( NULL != mImpl->mEventData )
1241   {
1242     // When the text is being modified, delay cursor blinking
1243     mImpl->mEventData->mDecorator->DelayCursorBlink();
1244   }
1245
1246   // Discard temporary text
1247   events.Clear();
1248 }
1249
1250 void Controller::ResetText()
1251 {
1252   // Reset buffers.
1253   mImpl->mLogicalModel->mText.Clear();
1254
1255   // We have cleared everything including the placeholder-text
1256   mImpl->PlaceholderCleared();
1257
1258   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1259   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1260   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
1261
1262   // Clear any previous text.
1263   mImpl->mTextUpdateInfo.mClearAll = true;
1264
1265   // The natural size needs to be re-calculated.
1266   mImpl->mRecalculateNaturalSize = true;
1267
1268   // Apply modifications to the model
1269   mImpl->mOperationsPending = ALL_OPERATIONS;
1270 }
1271
1272 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
1273 {
1274   // Reset the cursor position
1275   if( NULL != mImpl->mEventData )
1276   {
1277     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
1278
1279     // Update the cursor if it's in editing mode.
1280     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
1281     {
1282       mImpl->mEventData->mUpdateCursorPosition = true;
1283     }
1284   }
1285 }
1286
1287 void Controller::ResetScrollPosition()
1288 {
1289   if( NULL != mImpl->mEventData )
1290   {
1291     // Reset the scroll position.
1292     mImpl->mEventData->mScrollPosition = Vector2::ZERO;
1293     mImpl->mEventData->mScrollAfterUpdatePosition = true;
1294   }
1295 }
1296
1297 void Controller::TextReplacedEvent()
1298 {
1299   // The natural size needs to be re-calculated.
1300   mImpl->mRecalculateNaturalSize = true;
1301
1302   // Apply modifications to the model
1303   mImpl->mOperationsPending = ALL_OPERATIONS;
1304 }
1305
1306 void Controller::TextInsertedEvent()
1307 {
1308   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
1309
1310   if( NULL == mImpl->mEventData )
1311   {
1312     return;
1313   }
1314
1315   // The natural size needs to be re-calculated.
1316   mImpl->mRecalculateNaturalSize = true;
1317
1318   // Apply modifications to the model; TODO - Optimize this
1319   mImpl->mOperationsPending = ALL_OPERATIONS;
1320
1321   // Queue a cursor reposition event; this must wait until after DoRelayout()
1322   if( EventData::IsEditingState( mImpl->mEventData->mState ) )
1323   {
1324     mImpl->mEventData->mUpdateCursorPosition = true;
1325     mImpl->mEventData->mScrollAfterUpdatePosition = true;
1326   }
1327 }
1328
1329 void Controller::TextDeletedEvent()
1330 {
1331   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
1332
1333   if( NULL == mImpl->mEventData )
1334   {
1335     return;
1336   }
1337
1338   // The natural size needs to be re-calculated.
1339   mImpl->mRecalculateNaturalSize = true;
1340
1341   // Apply modifications to the model; TODO - Optimize this
1342   mImpl->mOperationsPending = ALL_OPERATIONS;
1343
1344   // Queue a cursor reposition event; this must wait until after DoRelayout()
1345   mImpl->mEventData->mUpdateCursorPosition = true;
1346   if( 0u != mImpl->mLogicalModel->mText.Count() )
1347   {
1348     mImpl->mEventData->mScrollAfterDelete = true;
1349   }
1350 }
1351
1352 bool Controller::DoRelayout( const Size& size,
1353                              OperationsMask operationsRequired,
1354                              Size& layoutSize )
1355 {
1356   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
1357   bool viewUpdated( false );
1358
1359   // Calculate the operations to be done.
1360   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1361
1362   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
1363   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
1364
1365   if( LAYOUT & operations )
1366   {
1367     // Some vectors with data needed to layout and reorder may be void
1368     // after the first time the text has been laid out.
1369     // Fill the vectors again.
1370
1371     // Calculate the number of glyphs to layout.
1372     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mVisualModel->mCharactersToGlyph;
1373     const Vector<Length>& glyphsPerCharacter = mImpl->mVisualModel->mGlyphsPerCharacter;
1374     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
1375     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
1376
1377     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
1378     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
1379     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
1380     const Length totalNumberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
1381
1382     if( 0u == totalNumberOfGlyphs )
1383     {
1384       if( UPDATE_ACTUAL_SIZE & operations )
1385       {
1386         mImpl->mVisualModel->SetLayoutSize( Size::ZERO );
1387       }
1388
1389       // Nothing else to do if there is no glyphs.
1390       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
1391       return true;
1392     }
1393
1394     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1395     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1396     const Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
1397     const Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1398     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1399     const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1400     const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
1401
1402     // Set the layout parameters.
1403     LayoutParameters layoutParameters( size,
1404                                        textBuffer,
1405                                        lineBreakInfo.Begin(),
1406                                        wordBreakInfo.Begin(),
1407                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
1408                                        glyphs.Begin(),
1409                                        glyphsToCharactersMap.Begin(),
1410                                        charactersPerGlyph.Begin(),
1411                                        charactersToGlyphBuffer,
1412                                        glyphsPerCharacterBuffer,
1413                                        totalNumberOfGlyphs );
1414
1415     // Resize the vector of positions to have the same size than the vector of glyphs.
1416     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1417     glyphPositions.Resize( totalNumberOfGlyphs );
1418
1419     // Whether the last character is a new paragraph character.
1420     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
1421     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
1422
1423     // The initial glyph and the number of glyphs to layout.
1424     layoutParameters.startGlyphIndex = startGlyphIndex;
1425     layoutParameters.numberOfGlyphs = numberOfGlyphs;
1426     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
1427     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
1428
1429     // Update the visual model.
1430     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1431                                                    glyphPositions,
1432                                                    mImpl->mVisualModel->mLines,
1433                                                    layoutSize );
1434
1435     if( viewUpdated )
1436     {
1437       // Reorder the lines
1438       if( REORDER & operations )
1439       {
1440         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1441         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mLogicalModel->mBidirectionalLineInfo;
1442
1443         // Check first if there are paragraphs with bidirectional info.
1444         if( 0u != bidirectionalInfo.Count() )
1445         {
1446           // Get the lines
1447           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
1448
1449           // Reorder the lines.
1450           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1451           ReorderLines( bidirectionalInfo,
1452                         startIndex,
1453                         requestedNumberOfCharacters,
1454                         mImpl->mVisualModel->mLines,
1455                         bidirectionalLineInfo );
1456
1457           // Set the bidirectional info per line into the layout parameters.
1458           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
1459           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
1460
1461           // TODO: update the conversion map instead creating it from scratch.
1462           //       Note this tables store indices to characters, so update the table means modify all the indices of the text after the last updated character.
1463           //       It's better to refactor this. Store this table per line and don't update the indices.
1464           //       For the cursor position probably is better to use the function instead creating a table.
1465           // Set the bidirectional info into the model.
1466           mImpl->mLogicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
1467                                                        layoutParameters.numberOfBidirectionalInfoRuns,
1468                                                        0u,
1469                                                        mImpl->mLogicalModel->mText.Count() );
1470
1471           // Re-layout the text. Reorder those lines with right to left characters.
1472           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1473                                                          startIndex,
1474                                                          requestedNumberOfCharacters,
1475                                                          glyphPositions );
1476
1477         }
1478       } // REORDER
1479
1480       // Sets the actual size.
1481       if( UPDATE_ACTUAL_SIZE & operations )
1482       {
1483         mImpl->mVisualModel->SetLayoutSize( layoutSize );
1484       }
1485     } // view updated
1486
1487     // Store the size used to layout the text.
1488     mImpl->mVisualModel->mControlSize = size;
1489   }
1490   else
1491   {
1492     layoutSize = mImpl->mVisualModel->GetLayoutSize();
1493   }
1494
1495   if( ALIGN & operations )
1496   {
1497     // The laid-out lines.
1498     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1499
1500     mImpl->mLayoutEngine.Align( size,
1501                                 startIndex,
1502                                 requestedNumberOfCharacters,
1503                                 lines );
1504
1505     viewUpdated = true;
1506   }
1507
1508   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
1509   return viewUpdated;
1510 }
1511
1512 void Controller::SetMultiLineEnabled( bool enable )
1513 {
1514   const LayoutEngine::Layout layout = enable ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
1515
1516   if( layout != mImpl->mLayoutEngine.GetLayout() )
1517   {
1518     // Set the layout type.
1519     mImpl->mLayoutEngine.SetLayout( layout );
1520
1521     // Set the flags to redo the layout operations
1522     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
1523                                                                           UPDATE_ACTUAL_SIZE |
1524                                                                           ALIGN              |
1525                                                                           REORDER );
1526
1527     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
1528
1529     mImpl->RequestRelayout();
1530   }
1531 }
1532
1533 bool Controller::IsMultiLineEnabled() const
1534 {
1535   return LayoutEngine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
1536 }
1537
1538 void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment alignment )
1539 {
1540   if( alignment != mImpl->mLayoutEngine.GetHorizontalAlignment() )
1541   {
1542     // Set the alignment.
1543     mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
1544
1545     // Set the flag to redo the alignment operation.
1546     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1547
1548     mImpl->RequestRelayout();
1549   }
1550 }
1551
1552 LayoutEngine::HorizontalAlignment Controller::GetHorizontalAlignment() const
1553 {
1554   return mImpl->mLayoutEngine.GetHorizontalAlignment();
1555 }
1556
1557 void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment )
1558 {
1559   if( alignment != mImpl->mLayoutEngine.GetVerticalAlignment() )
1560   {
1561     // Set the alignment.
1562     mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
1563
1564     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1565
1566     mImpl->RequestRelayout();
1567   }
1568 }
1569
1570 LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
1571 {
1572   return mImpl->mLayoutEngine.GetVerticalAlignment();
1573 }
1574
1575 void Controller::CalculateTextAlignment( const Size& controlSize )
1576 {
1577   Size layoutSize = mImpl->mVisualModel->GetLayoutSize();
1578
1579   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
1580   {
1581     // Get the line height of the default font.
1582     layoutSize.height = mImpl->GetDefaultFontLineHeight();
1583   }
1584
1585   if( LayoutEngine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
1586   {
1587     // Get the direction of the first character.
1588     const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
1589
1590     // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
1591     LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
1592     if( firstParagraphDirection )
1593     {
1594       switch( horizontalAlignment )
1595       {
1596         case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1597         {
1598           horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
1599           break;
1600         }
1601         case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1602         {
1603           // Nothing to do.
1604           break;
1605         }
1606         case LayoutEngine::HORIZONTAL_ALIGN_END:
1607         {
1608           horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
1609           break;
1610         }
1611       }
1612     }
1613
1614     switch( horizontalAlignment )
1615     {
1616       case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1617       {
1618         mImpl->mAlignmentOffset.x = 0.f;
1619         break;
1620       }
1621       case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1622       {
1623         mImpl->mAlignmentOffset.x = floorf( 0.5f * ( controlSize.width - layoutSize.width ) ); // try to avoid pixel alignment.
1624         break;
1625       }
1626       case LayoutEngine::HORIZONTAL_ALIGN_END:
1627       {
1628         mImpl->mAlignmentOffset.x = controlSize.width - layoutSize.width;
1629         break;
1630       }
1631     }
1632   }
1633
1634   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1635   switch( verticalAlignment )
1636   {
1637     case LayoutEngine::VERTICAL_ALIGN_TOP:
1638     {
1639       mImpl->mAlignmentOffset.y = 0.f;
1640       break;
1641     }
1642     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1643     {
1644       mImpl->mAlignmentOffset.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
1645       break;
1646     }
1647     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1648     {
1649       mImpl->mAlignmentOffset.y = controlSize.height - layoutSize.height;
1650       break;
1651     }
1652   }
1653 }
1654
1655 LayoutEngine& Controller::GetLayoutEngine()
1656 {
1657   return mImpl->mLayoutEngine;
1658 }
1659
1660 View& Controller::GetView()
1661 {
1662   return mImpl->mView;
1663 }
1664
1665 void Controller::KeyboardFocusGainEvent()
1666 {
1667   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1668
1669   if( NULL != mImpl->mEventData )
1670   {
1671     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
1672         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
1673     {
1674       mImpl->ChangeState( EventData::EDITING );
1675       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
1676     }
1677
1678     if( mImpl->IsShowingPlaceholderText() )
1679     {
1680       // Show alternative placeholder-text when editing
1681       ShowPlaceholderText();
1682     }
1683
1684     mImpl->RequestRelayout();
1685   }
1686 }
1687
1688 void Controller::KeyboardFocusLostEvent()
1689 {
1690   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1691
1692   if( NULL != mImpl->mEventData )
1693   {
1694     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
1695     {
1696       mImpl->ChangeState( EventData::INACTIVE );
1697
1698       if( !mImpl->IsShowingRealText() )
1699       {
1700         // Revert to regular placeholder-text when not editing
1701         ShowPlaceholderText();
1702       }
1703     }
1704   }
1705   mImpl->RequestRelayout();
1706 }
1707
1708 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1709 {
1710   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1711
1712   bool textChanged( false );
1713
1714   if( ( NULL != mImpl->mEventData ) &&
1715       ( keyEvent.state == KeyEvent::Down ) )
1716   {
1717     int keyCode = keyEvent.keyCode;
1718     const std::string& keyString = keyEvent.keyPressed;
1719
1720     // Pre-process to separate modifying events from non-modifying input events.
1721     if( Dali::DALI_KEY_ESCAPE == keyCode )
1722     {
1723       // Escape key is a special case which causes focus loss
1724       KeyboardFocusLostEvent();
1725     }
1726     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
1727              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
1728              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
1729              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
1730     {
1731       Event event( Event::CURSOR_KEY_EVENT );
1732       event.p1.mInt = keyCode;
1733       mImpl->mEventData->mEventQueue.push_back( event );
1734     }
1735     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1736     {
1737       textChanged = BackspaceKeyEvent();
1738     }
1739     else if( IsKey( keyEvent,  Dali::DALI_KEY_POWER ) )
1740     {
1741       mImpl->ChangeState( EventData::INTERRUPTED ); // State is not INACTIVE as expect to return to edit mode.
1742       // Avoids calling the InsertText() method which can delete selected text
1743     }
1744     else if( IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
1745              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
1746     {
1747       mImpl->ChangeState( EventData::INACTIVE );
1748       // Menu/Home key behaviour does not allow edit mode to resume like Power key
1749       // Avoids calling the InsertText() method which can delete selected text
1750     }
1751     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
1752     {
1753       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
1754       // and a character is typed after the type of a upper case latin character.
1755
1756       // Do nothing.
1757     }
1758     else
1759     {
1760       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
1761
1762       // IMF manager is no longer handling key-events
1763       mImpl->ClearPreEditFlag();
1764
1765       InsertText( keyString, COMMIT );
1766       textChanged = true;
1767     }
1768
1769     if( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
1770         ( mImpl->mEventData->mState != EventData::INACTIVE ) )
1771     {
1772       mImpl->ChangeState( EventData::EDITING );
1773     }
1774
1775     mImpl->RequestRelayout();
1776   }
1777
1778   if( textChanged )
1779   {
1780     // Do this last since it provides callbacks into application code
1781     mImpl->mControlInterface.TextChanged();
1782   }
1783
1784   return true;
1785 }
1786
1787 void Controller::InsertText( const std::string& text, Controller::InsertType type )
1788 {
1789   bool removedPrevious( false );
1790   bool maxLengthReached( false );
1791
1792   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
1793
1794   if( NULL == mImpl->mEventData )
1795   {
1796     return;
1797   }
1798
1799   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
1800                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
1801                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1802
1803   // TODO: At the moment the underline runs are only for pre-edit.
1804   mImpl->mVisualModel->mUnderlineRuns.Clear();
1805
1806   Vector<Character> utf32Characters;
1807   Length characterCount( 0u );
1808
1809   // Remove the previous IMF pre-edit (predicitive text)
1810   if( mImpl->mEventData->mPreEditFlag &&
1811       ( 0u != mImpl->mEventData->mPreEditLength ) )
1812   {
1813     const CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
1814
1815     removedPrevious = RemoveText( -static_cast<int>( offset ), mImpl->mEventData->mPreEditLength );
1816
1817     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
1818     mImpl->mEventData->mPreEditLength = 0u;
1819   }
1820   else
1821   {
1822     // Remove the previous Selection
1823     removedPrevious = RemoveSelectedText();
1824   }
1825
1826   if( !text.empty() )
1827   {
1828     //  Convert text into UTF-32
1829     utf32Characters.Resize( text.size() );
1830
1831     // This is a bit horrible but std::string returns a (signed) char*
1832     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1833
1834     // Transform a text array encoded in utf8 into an array encoded in utf32.
1835     // It returns the actual number of characters.
1836     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1837     utf32Characters.Resize( characterCount );
1838
1839     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
1840     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
1841   }
1842
1843   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
1844   {
1845     // The placeholder text is no longer needed
1846     if( mImpl->IsShowingPlaceholderText() )
1847     {
1848       ResetText();
1849     }
1850
1851     mImpl->ChangeState( EventData::EDITING );
1852
1853     // Handle the IMF (predicitive text) state changes
1854     if( COMMIT == type )
1855     {
1856       // IMF manager is no longer handling key-events
1857       mImpl->ClearPreEditFlag();
1858     }
1859     else // PRE_EDIT
1860     {
1861       if( !mImpl->mEventData->mPreEditFlag )
1862       {
1863         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state" );
1864
1865         // Record the start of the pre-edit text
1866         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
1867       }
1868
1869       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
1870       mImpl->mEventData->mPreEditFlag = true;
1871
1872       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1873     }
1874
1875     const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
1876
1877     // Restrict new text to fit within Maximum characters setting.
1878     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
1879     maxLengthReached = ( characterCount > maxSizeOfNewText );
1880
1881     // The cursor position.
1882     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
1883
1884     // Update the text's style.
1885
1886     // Updates the text style runs by adding characters.
1887     mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
1888
1889     // Get the character index from the cursor index.
1890     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
1891
1892     // Retrieve the text's style for the given index.
1893     InputStyle style;
1894     mImpl->mLogicalModel->RetrieveStyle( styleIndex, style );
1895
1896     // Whether to add a new text color run.
1897     const bool addColorRun = style.textColor != mImpl->mEventData->mInputStyle.textColor;
1898
1899     // Whether to add a new font run.
1900     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
1901     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
1902     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
1903     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
1904     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
1905
1906     // Add style runs.
1907     if( addColorRun )
1908     {
1909       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
1910       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1911
1912       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1913       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
1914       colorRun.characterRun.characterIndex = cursorIndex;
1915       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
1916     }
1917
1918     if( addFontNameRun   ||
1919         addFontWeightRun ||
1920         addFontWidthRun  ||
1921         addFontSlantRun  ||
1922         addFontSizeRun )
1923     {
1924       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mFontDescriptionRuns.Count();
1925       mImpl->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
1926
1927       FontDescriptionRun& fontDescriptionRun = *( mImpl->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
1928
1929       if( addFontNameRun )
1930       {
1931         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
1932         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
1933         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
1934         fontDescriptionRun.familyDefined = true;
1935
1936         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
1937       }
1938
1939       if( addFontWeightRun )
1940       {
1941         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
1942         fontDescriptionRun.weightDefined = true;
1943       }
1944
1945       if( addFontWidthRun )
1946       {
1947         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
1948         fontDescriptionRun.widthDefined = true;
1949       }
1950
1951       if( addFontSlantRun )
1952       {
1953         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
1954         fontDescriptionRun.slantDefined = true;
1955       }
1956
1957       if( addFontSizeRun )
1958       {
1959         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
1960         fontDescriptionRun.sizeDefined = true;
1961       }
1962
1963       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
1964       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
1965     }
1966
1967     // Insert at current cursor position.
1968     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1969
1970     if( cursorIndex < numberOfCharactersInModel )
1971     {
1972       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1973     }
1974     else
1975     {
1976       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1977     }
1978
1979     // Mark the first paragraph to be updated.
1980     mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
1981     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
1982
1983     // Update the cursor index.
1984     cursorIndex += maxSizeOfNewText;
1985
1986     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
1987   }
1988
1989   if( ( 0u == mImpl->mLogicalModel->mText.Count() ) &&
1990       mImpl->IsPlaceholderAvailable() )
1991   {
1992     // Show place-holder if empty after removing the pre-edit text
1993     ShowPlaceholderText();
1994     mImpl->mEventData->mUpdateCursorPosition = true;
1995     mImpl->ClearPreEditFlag();
1996   }
1997   else if( removedPrevious ||
1998            ( 0 != utf32Characters.Count() ) )
1999   {
2000     // Queue an inserted event
2001     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
2002   }
2003
2004   if( maxLengthReached )
2005   {
2006     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
2007
2008     mImpl->ResetImfManager();
2009
2010     // Do this last since it provides callbacks into application code
2011     mImpl->mControlInterface.MaxLengthReached();
2012   }
2013 }
2014
2015 bool Controller::RemoveSelectedText()
2016 {
2017   bool textRemoved( false );
2018
2019   if( EventData::SELECTING == mImpl->mEventData->mState )
2020   {
2021     std::string removedString;
2022     mImpl->RetrieveSelection( removedString, true );
2023
2024     if( !removedString.empty() )
2025     {
2026       textRemoved = true;
2027       mImpl->ChangeState( EventData::EDITING );
2028     }
2029   }
2030
2031   return textRemoved;
2032 }
2033
2034 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2035 {
2036   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2037
2038   if( NULL != mImpl->mEventData )
2039   {
2040     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2041
2042     if( 1u == tapCount )
2043     {
2044       // This is to avoid unnecessary relayouts when tapping an empty text-field
2045       bool relayoutNeeded( false );
2046
2047       if( ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) ||
2048           ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
2049       {
2050         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE);  // If Popup shown hide it here so can be shown again if required.
2051       }
2052
2053       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != mImpl->mEventData->mState ) )
2054       {
2055         // Already in an active state so show a popup
2056         if( !mImpl->IsClipboardEmpty() )
2057         {
2058           // Shows Paste popup but could show full popup with Selection options. ( EDITING_WITH_POPUP )
2059           mImpl->ChangeState( EventData::EDITING_WITH_PASTE_POPUP );
2060         }
2061         else
2062         {
2063           mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2064         }
2065         relayoutNeeded = true;
2066       }
2067       else
2068       {
2069         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2070         {
2071           // Hide placeholder text
2072           ResetText();
2073         }
2074
2075         if( EventData::INACTIVE == mImpl->mEventData->mState )
2076         {
2077           mImpl->ChangeState( EventData::EDITING );
2078         }
2079         else if( !mImpl->IsClipboardEmpty() )
2080         {
2081           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2082         }
2083         relayoutNeeded = true;
2084       }
2085
2086       // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2087       if( relayoutNeeded )
2088       {
2089         Event event( Event::TAP_EVENT );
2090         event.p1.mUint = tapCount;
2091         event.p2.mFloat = x;
2092         event.p3.mFloat = y;
2093         mImpl->mEventData->mEventQueue.push_back( event );
2094
2095         mImpl->RequestRelayout();
2096       }
2097     }
2098     else if( 2u == tapCount )
2099     {
2100       if( mImpl->mEventData->mSelectionEnabled &&
2101           mImpl->IsShowingRealText() )
2102       {
2103         SelectEvent( x, y, false );
2104       }
2105     }
2106   }
2107
2108   // Reset keyboard as tap event has occurred.
2109   mImpl->ResetImfManager();
2110 }
2111
2112 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2113         // Show cursor and grabhandle on first tap, this matches the behaviour of tapping when already editing
2114 {
2115   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2116
2117   if( NULL != mImpl->mEventData )
2118   {
2119     Event event( Event::PAN_EVENT );
2120     event.p1.mInt = state;
2121     event.p2.mFloat = displacement.x;
2122     event.p3.mFloat = displacement.y;
2123     mImpl->mEventData->mEventQueue.push_back( event );
2124
2125     mImpl->RequestRelayout();
2126   }
2127 }
2128
2129 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2130 {
2131   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2132
2133   if( ( state == Gesture::Started ) &&
2134       ( NULL != mImpl->mEventData ) )
2135   {
2136     if( !mImpl->IsShowingRealText() )
2137     {
2138       Event event( Event::LONG_PRESS_EVENT );
2139       event.p1.mInt = state;
2140       mImpl->mEventData->mEventQueue.push_back( event );
2141       mImpl->RequestRelayout();
2142     }
2143     else
2144     {
2145       // The 1st long-press on inactive text-field is treated as tap
2146       if( EventData::INACTIVE == mImpl->mEventData->mState )
2147       {
2148         mImpl->ChangeState( EventData::EDITING );
2149
2150         Event event( Event::TAP_EVENT );
2151         event.p1.mUint = 1;
2152         event.p2.mFloat = x;
2153         event.p3.mFloat = y;
2154         mImpl->mEventData->mEventQueue.push_back( event );
2155
2156         mImpl->RequestRelayout();
2157       }
2158       else
2159       {
2160         // Reset the imf manger to commit the pre-edit before selecting the text.
2161         mImpl->ResetImfManager();
2162
2163         SelectEvent( x, y, false );
2164       }
2165     }
2166   }
2167 }
2168
2169 void Controller::SelectEvent( float x, float y, bool selectAll )
2170 {
2171   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
2172
2173   if( NULL != mImpl->mEventData )
2174   {
2175     mImpl->ChangeState( EventData::SELECTING );
2176
2177     if( selectAll )
2178     {
2179       Event event( Event::SELECT_ALL );
2180       mImpl->mEventData->mEventQueue.push_back( event );
2181     }
2182     else
2183     {
2184       Event event( Event::SELECT );
2185       event.p2.mFloat = x;
2186       event.p3.mFloat = y;
2187       mImpl->mEventData->mEventQueue.push_back( event );
2188     }
2189
2190     mImpl->RequestRelayout();
2191   }
2192 }
2193
2194 void Controller::GetTargetSize( Vector2& targetSize )
2195 {
2196   targetSize = mImpl->mVisualModel->mControlSize;
2197 }
2198
2199 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2200 {
2201   mImpl->mControlInterface.AddDecoration( actor, needsClipping );
2202 }
2203
2204 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2205 {
2206   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2207
2208   if( NULL != mImpl->mEventData )
2209   {
2210     switch( handleType )
2211     {
2212       case GRAB_HANDLE:
2213       {
2214         Event event( Event::GRAB_HANDLE_EVENT );
2215         event.p1.mUint  = state;
2216         event.p2.mFloat = x;
2217         event.p3.mFloat = y;
2218
2219         mImpl->mEventData->mEventQueue.push_back( event );
2220         break;
2221       }
2222       case LEFT_SELECTION_HANDLE:
2223       {
2224         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2225         event.p1.mUint  = state;
2226         event.p2.mFloat = x;
2227         event.p3.mFloat = y;
2228
2229         mImpl->mEventData->mEventQueue.push_back( event );
2230         break;
2231       }
2232       case RIGHT_SELECTION_HANDLE:
2233       {
2234         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2235         event.p1.mUint  = state;
2236         event.p2.mFloat = x;
2237         event.p3.mFloat = y;
2238
2239         mImpl->mEventData->mEventQueue.push_back( event );
2240         break;
2241       }
2242       case LEFT_SELECTION_HANDLE_MARKER:
2243       case RIGHT_SELECTION_HANDLE_MARKER:
2244       {
2245         // Markers do not move the handles.
2246         break;
2247       }
2248       case HANDLE_TYPE_COUNT:
2249       {
2250         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2251       }
2252     }
2253
2254     mImpl->RequestRelayout();
2255   }
2256 }
2257
2258 void Controller::PasteText( const std::string& stringToPaste )
2259 {
2260   InsertText( stringToPaste, Text::Controller::COMMIT );
2261   mImpl->ChangeState( EventData::EDITING );
2262   mImpl->RequestRelayout();
2263
2264   // Do this last since it provides callbacks into application code
2265   mImpl->mControlInterface.TextChanged();
2266 }
2267
2268 void Controller::PasteClipboardItemEvent()
2269 {
2270   // Retrieve the clipboard contents first
2271   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2272   std::string stringToPaste( notifier.GetContent() );
2273
2274   // Commit the current pre-edit text; the contents of the clipboard should be appended
2275   mImpl->ResetImfManager();
2276
2277   // Paste
2278   PasteText( stringToPaste );
2279 }
2280
2281 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2282 {
2283   if( NULL == mImpl->mEventData )
2284   {
2285     return;
2286   }
2287
2288   switch( button )
2289   {
2290     case Toolkit::TextSelectionPopup::CUT:
2291     {
2292       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2293       mImpl->mOperationsPending = ALL_OPERATIONS;
2294
2295       // This is to reset the virtual keyboard to Upper-case
2296       if( 0u == mImpl->mLogicalModel->mText.Count() )
2297       {
2298         NotifyImfManager();
2299       }
2300
2301       if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2302           !mImpl->IsPlaceholderAvailable() )
2303       {
2304         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2305       }
2306       else
2307       {
2308         ShowPlaceholderText();
2309         mImpl->mEventData->mUpdateCursorPosition = true;
2310       }
2311       mImpl->RequestRelayout();
2312       mImpl->mControlInterface.TextChanged();
2313       break;
2314     }
2315     case Toolkit::TextSelectionPopup::COPY:
2316     {
2317       mImpl->SendSelectionToClipboard( false ); // Text not modified
2318       mImpl->RequestRelayout(); // Handles, Selection Highlight, Popup
2319       break;
2320     }
2321     case Toolkit::TextSelectionPopup::PASTE:
2322     {
2323       std::string stringToPaste("");
2324       mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
2325       PasteText( stringToPaste );
2326       break;
2327     }
2328     case Toolkit::TextSelectionPopup::SELECT:
2329     {
2330       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2331
2332       if( mImpl->mEventData->mSelectionEnabled )
2333       {
2334         // Creates a SELECT event.
2335         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2336       }
2337       break;
2338     }
2339     case Toolkit::TextSelectionPopup::SELECT_ALL:
2340     {
2341       // Creates a SELECT_ALL event
2342       SelectEvent( 0.f, 0.f, true );
2343       break;
2344     }
2345     case Toolkit::TextSelectionPopup::CLIPBOARD:
2346     {
2347       mImpl->ShowClipboard();
2348       break;
2349     }
2350     case Toolkit::TextSelectionPopup::NONE:
2351     {
2352       // Nothing to do.
2353       break;
2354     }
2355   }
2356 }
2357
2358 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2359 {
2360   bool update = false;
2361   bool requestRelayout = false;
2362
2363   std::string text;
2364   unsigned int cursorPosition = 0u;
2365
2366   switch( imfEvent.eventName )
2367   {
2368     case ImfManager::COMMIT:
2369     {
2370       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2371       update = true;
2372       requestRelayout = true;
2373       break;
2374     }
2375     case ImfManager::PREEDIT:
2376     {
2377       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2378       update = true;
2379       requestRelayout = true;
2380       break;
2381     }
2382     case ImfManager::DELETESURROUNDING:
2383     {
2384       update = RemoveText( imfEvent.cursorOffset, imfEvent.numberOfChars );
2385
2386       if( update )
2387       {
2388         if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2389             !mImpl->IsPlaceholderAvailable() )
2390         {
2391           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2392         }
2393         else
2394         {
2395           ShowPlaceholderText();
2396           mImpl->mEventData->mUpdateCursorPosition = true;
2397         }
2398       }
2399       requestRelayout = true;
2400       break;
2401     }
2402     case ImfManager::GETSURROUNDING:
2403     {
2404       GetText( text );
2405       cursorPosition = GetLogicalCursorPosition();
2406
2407       imfManager.SetSurroundingText( text );
2408       imfManager.SetCursorPosition( cursorPosition );
2409       break;
2410     }
2411     case ImfManager::VOID:
2412     {
2413       // do nothing
2414       break;
2415     }
2416   } // end switch
2417
2418   if( ImfManager::GETSURROUNDING != imfEvent.eventName )
2419   {
2420     GetText( text );
2421     cursorPosition = GetLogicalCursorPosition();
2422   }
2423
2424   if( requestRelayout )
2425   {
2426     mImpl->mOperationsPending = ALL_OPERATIONS;
2427     mImpl->RequestRelayout();
2428
2429     // Do this last since it provides callbacks into application code
2430     mImpl->mControlInterface.TextChanged();
2431   }
2432
2433   ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
2434
2435   return callbackData;
2436 }
2437
2438 Controller::~Controller()
2439 {
2440   delete mImpl;
2441 }
2442
2443 bool Controller::BackspaceKeyEvent()
2444 {
2445   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
2446
2447   bool removed = false;
2448
2449   if( NULL == mImpl->mEventData )
2450   {
2451     return removed;
2452   }
2453
2454   // IMF manager is no longer handling key-events
2455   mImpl->ClearPreEditFlag();
2456
2457   if( EventData::SELECTING == mImpl->mEventData->mState )
2458   {
2459     removed = RemoveSelectedText();
2460   }
2461   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
2462   {
2463     // Remove the character before the current cursor position
2464     removed = RemoveText( -1, 1 );
2465   }
2466
2467   if( removed )
2468   {
2469     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE RemovedText\n", this );
2470     // Notifiy the IMF manager after text changed
2471     // Automatic  Upper-case and restarting prediction on an existing word require this.
2472     NotifyImfManager();
2473
2474     if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2475         !mImpl->IsPlaceholderAvailable() )
2476     {
2477       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2478     }
2479     else
2480     {
2481       ShowPlaceholderText();
2482       mImpl->mEventData->mUpdateCursorPosition = true;
2483     }
2484   }
2485
2486   return removed;
2487 }
2488
2489 void Controller::NotifyImfManager()
2490 {
2491   if( NULL != mImpl->mEventData )
2492   {
2493     if( mImpl->mEventData->mImfManager )
2494     {
2495       // Notifying IMF of a cursor change triggers a surrounding text request so updating it now.
2496       std::string text;
2497       GetText( text );
2498       mImpl->mEventData->mImfManager.SetSurroundingText( text );
2499
2500       mImpl->mEventData->mImfManager.SetCursorPosition( GetLogicalCursorPosition() );
2501       mImpl->mEventData->mImfManager.NotifyCursorPosition();
2502     }
2503   }
2504 }
2505
2506 void Controller::ShowPlaceholderText()
2507 {
2508   if( mImpl->IsPlaceholderAvailable() )
2509   {
2510     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
2511
2512     if( NULL == mImpl->mEventData )
2513     {
2514       return;
2515     }
2516
2517     mImpl->mEventData->mIsShowingPlaceholderText = true;
2518
2519     // Disable handles when showing place-holder text
2520     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2521     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2522     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2523
2524     const char* text( NULL );
2525     size_t size( 0 );
2526
2527     // TODO - Switch placeholder text styles when changing state
2528     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
2529         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
2530     {
2531       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
2532       size = mImpl->mEventData->mPlaceholderTextActive.size();
2533     }
2534     else
2535     {
2536       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
2537       size = mImpl->mEventData->mPlaceholderTextInactive.size();
2538     }
2539
2540     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2541     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2542
2543     // Reset model for showing placeholder.
2544     mImpl->mLogicalModel->mText.Clear();
2545     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
2546
2547     // Convert text into UTF-32
2548     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
2549     utf32Characters.Resize( size );
2550
2551     // This is a bit horrible but std::string returns a (signed) char*
2552     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
2553
2554     // Transform a text array encoded in utf8 into an array encoded in utf32.
2555     // It returns the actual number of characters.
2556     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
2557     utf32Characters.Resize( characterCount );
2558
2559     // The characters to be added.
2560     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
2561
2562     // Reset the cursor position
2563     mImpl->mEventData->mPrimaryCursorPosition = 0;
2564
2565     // The natural size needs to be re-calculated.
2566     mImpl->mRecalculateNaturalSize = true;
2567
2568     // Apply modifications to the model
2569     mImpl->mOperationsPending = ALL_OPERATIONS;
2570
2571     // Update the rest of the model during size negotiation
2572     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
2573   }
2574 }
2575
2576 void Controller::ClearFontData()
2577 {
2578   if( mImpl->mFontDefaults )
2579   {
2580     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
2581   }
2582   mImpl->mLogicalModel->mFontRuns.Clear();
2583   mImpl->mVisualModel->mGlyphs.Clear();
2584   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
2585   mImpl->mVisualModel->mCharactersToGlyph.Clear();
2586   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
2587   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
2588   mImpl->mVisualModel->mGlyphPositions.Clear();
2589   mImpl->mVisualModel->mLines.Clear();
2590   mImpl->mVisualModel->ClearCaches();
2591 }
2592
2593 void Controller::ClearStyleData()
2594 {
2595   mImpl->mLogicalModel->mColorRuns.Clear();
2596   mImpl->mLogicalModel->ClearFontDescriptionRuns();
2597 }
2598
2599 Controller::Controller( ControlInterface& controlInterface )
2600 : mImpl( NULL )
2601 {
2602   mImpl = new Controller::Impl( controlInterface );
2603 }
2604
2605 } // namespace Text
2606
2607 } // namespace Toolkit
2608
2609 } // namespace Dali