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