Merge "[4.0] Support Right-To-Left of padding/margin in imageView" into tizen_4.0
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2017 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 #include <dali/devel-api/text-abstraction/font-client.h>
28 #include <dali/devel-api/adaptor-framework/key-devel.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
32 #include <dali-toolkit/internal/text/bidirectional-support.h>
33 #include <dali-toolkit/internal/text/character-set-conversion.h>
34 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
35 #include <dali-toolkit/internal/text/markup-processor.h>
36 #include <dali-toolkit/internal/text/multi-language-support.h>
37 #include <dali-toolkit/internal/text/text-controller-impl.h>
38 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
39 #include <dali-toolkit/internal/text/text-font-style.h>
40
41 namespace
42 {
43
44 #if defined(DEBUG_ENABLED)
45   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
46 #endif
47
48 const float MAX_FLOAT = std::numeric_limits<float>::max();
49
50 const std::string EMPTY_STRING("");
51
52 const char * const PLACEHOLDER_TEXT = "text";
53 const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
54 const char * const PLACEHOLDER_COLOR = "color";
55 const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily";
56 const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
57 const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
58 const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
59 const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
60
61 float ConvertToEven( float value )
62 {
63   int intValue(static_cast<int>( value ));
64   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
65 }
66
67 } // namespace
68
69 namespace Dali
70 {
71
72 namespace Toolkit
73 {
74
75 namespace Text
76 {
77
78 /**
79  * @brief Adds a new font description run for the selected text.
80  *
81  * The new font parameters are added after the call to this method.
82  *
83  * @param[in] eventData The event data pointer.
84  * @param[in] logicalModel The logical model where to add the new font description run.
85  * @param[out] startOfSelectedText Index to the first selected character.
86  * @param[out] lengthOfSelectedText Number of selected characters.
87  */
88 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
89                                                  LogicalModelPtr logicalModel,
90                                                  CharacterIndex& startOfSelectedText,
91                                                  Length& lengthOfSelectedText )
92 {
93   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
94
95   // Get start and end position of selection
96   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
97   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
98
99   // Add the font run.
100   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
101   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
102
103   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
104
105   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
106   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
107
108   // Recalculate the selection highlight as the metrics may have changed.
109   eventData->mUpdateLeftSelectionPosition = true;
110   eventData->mUpdateRightSelectionPosition = true;
111   eventData->mUpdateHighlightBox = true;
112
113   return fontDescriptionRun;
114 }
115
116 // public : Constructor.
117
118 ControllerPtr Controller::New()
119 {
120   return ControllerPtr( new Controller() );
121 }
122
123 ControllerPtr Controller::New( ControlInterface* controlInterface )
124 {
125   return ControllerPtr( new Controller( controlInterface ) );
126 }
127
128 ControllerPtr Controller::New( ControlInterface* controlInterface,
129                                EditableControlInterface* editableControlInterface )
130 {
131   return ControllerPtr( new Controller( controlInterface,
132                                         editableControlInterface ) );
133 }
134
135 // public : Configure the text controller.
136
137 void Controller::EnableTextInput( DecoratorPtr decorator )
138 {
139   if( !decorator )
140   {
141     delete mImpl->mEventData;
142     mImpl->mEventData = NULL;
143
144     // Nothing else to do.
145     return;
146   }
147
148   if( NULL == mImpl->mEventData )
149   {
150     mImpl->mEventData = new EventData( decorator );
151   }
152 }
153
154 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
155 {
156   // Metrics for bitmap & vector based glyphs are different
157   mImpl->mMetrics->SetGlyphType( glyphType );
158
159   // Clear the font-specific data
160   ClearFontData();
161
162   mImpl->RequestRelayout();
163 }
164
165 void Controller::SetMarkupProcessorEnabled( bool enable )
166 {
167   mImpl->mMarkupProcessorEnabled = enable;
168   if( enable )
169   {
170     //If Text was already set, call the SetText again for enabling markup
171     std::string text;
172     GetText( text );
173     SetText( text );
174   }
175 }
176
177 bool Controller::IsMarkupProcessorEnabled() const
178 {
179   return mImpl->mMarkupProcessorEnabled;
180 }
181
182 void Controller::SetAutoScrollEnabled( bool enable )
183 {
184   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)?"true":"false", this );
185
186   if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
187   {
188     if( enable )
189     {
190       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
191       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
192                                                                LAYOUT                    |
193                                                                ALIGN                     |
194                                                                UPDATE_LAYOUT_SIZE        |
195                                                                UPDATE_DIRECTION          |
196                                                                REORDER );
197
198     }
199     else
200     {
201       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
202       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
203                                                                LAYOUT                    |
204                                                                ALIGN                     |
205                                                                UPDATE_LAYOUT_SIZE        |
206                                                                REORDER );
207     }
208
209     mImpl->mIsAutoScrollEnabled = enable;
210     mImpl->RequestRelayout();
211   }
212   else
213   {
214     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
215     mImpl->mIsAutoScrollEnabled = false;
216   }
217 }
218
219 bool Controller::IsAutoScrollEnabled() const
220 {
221   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
222
223   return mImpl->mIsAutoScrollEnabled;
224 }
225
226 CharacterDirection Controller::GetAutoScrollDirection() const
227 {
228   return mImpl->mAutoScrollDirectionRTL;
229 }
230
231 float Controller::GetAutoScrollLineAlignment() const
232 {
233   float offset = 0.f;
234
235   if( mImpl->mModel->mVisualModel &&
236       ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
237   {
238     offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
239   }
240
241   return offset;
242 }
243
244 void Controller::SetHorizontalScrollEnabled( bool enable )
245 {
246   if( ( NULL != mImpl->mEventData ) &&
247       mImpl->mEventData->mDecorator )
248   {
249     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
250   }
251 }
252 bool Controller::IsHorizontalScrollEnabled() const
253 {
254   if( ( NULL != mImpl->mEventData ) &&
255       mImpl->mEventData->mDecorator )
256   {
257     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
258   }
259
260   return false;
261 }
262
263 void Controller::SetVerticalScrollEnabled( bool enable )
264 {
265   if( ( NULL != mImpl->mEventData ) &&
266       mImpl->mEventData->mDecorator )
267   {
268     if( mImpl->mEventData->mDecorator )
269     {
270       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
271     }
272   }
273 }
274
275 bool Controller::IsVerticalScrollEnabled() const
276 {
277   if( ( NULL != mImpl->mEventData ) &&
278       mImpl->mEventData->mDecorator )
279   {
280     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
281   }
282
283   return false;
284 }
285
286 void Controller::SetSmoothHandlePanEnabled( bool enable )
287 {
288   if( ( NULL != mImpl->mEventData ) &&
289       mImpl->mEventData->mDecorator )
290   {
291     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
292   }
293 }
294
295 bool Controller::IsSmoothHandlePanEnabled() const
296 {
297   if( ( NULL != mImpl->mEventData ) &&
298       mImpl->mEventData->mDecorator )
299   {
300     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
301   }
302
303   return false;
304 }
305
306 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
307 {
308   mImpl->mMaximumNumberOfCharacters = maxCharacters;
309 }
310
311 int Controller::GetMaximumNumberOfCharacters()
312 {
313   return mImpl->mMaximumNumberOfCharacters;
314 }
315
316 void Controller::SetEnableCursorBlink( bool enable )
317 {
318   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
319
320   if( NULL != mImpl->mEventData )
321   {
322     mImpl->mEventData->mCursorBlinkEnabled = enable;
323
324     if( !enable &&
325         mImpl->mEventData->mDecorator )
326     {
327       mImpl->mEventData->mDecorator->StopCursorBlink();
328     }
329   }
330 }
331
332 bool Controller::GetEnableCursorBlink() const
333 {
334   if( NULL != mImpl->mEventData )
335   {
336     return mImpl->mEventData->mCursorBlinkEnabled;
337   }
338
339   return false;
340 }
341
342 void Controller::SetMultiLineEnabled( bool enable )
343 {
344   const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
345
346   if( layout != mImpl->mLayoutEngine.GetLayout() )
347   {
348     // Set the layout type.
349     mImpl->mLayoutEngine.SetLayout( layout );
350
351     // Set the flags to redo the layout operations
352     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
353                                                                           UPDATE_LAYOUT_SIZE |
354                                                                           ALIGN              |
355                                                                           REORDER );
356
357     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
358     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
359
360     mImpl->RequestRelayout();
361   }
362 }
363
364 bool Controller::IsMultiLineEnabled() const
365 {
366   return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
367 }
368
369 void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
370 {
371   if( alignment != mImpl->mModel->mHorizontalAlignment )
372   {
373     // Set the alignment.
374     mImpl->mModel->mHorizontalAlignment = alignment;
375
376     // Set the flag to redo the alignment operation.
377     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
378
379     mImpl->RequestRelayout();
380   }
381 }
382
383 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
384 {
385   return mImpl->mModel->mHorizontalAlignment;
386 }
387
388 void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
389 {
390   if( alignment != mImpl->mModel->mVerticalAlignment )
391   {
392     // Set the alignment.
393     mImpl->mModel->mVerticalAlignment = alignment;
394
395     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
396
397     mImpl->RequestRelayout();
398   }
399 }
400
401 VerticalAlignment::Type Controller::GetVerticalAlignment() const
402 {
403   return mImpl->mModel->mVerticalAlignment;
404 }
405
406 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
407 {
408   if( lineWrapMode != mImpl->mModel->mLineWrapMode )
409   {
410     // Set the text wrap mode.
411     mImpl->mModel->mLineWrapMode = lineWrapMode;
412
413
414     // Update Text layout for applying wrap mode
415     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
416                                                              ALIGN                     |
417                                                              LAYOUT                    |
418                                                              UPDATE_LAYOUT_SIZE        |
419                                                              REORDER                   );
420     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
421     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
422     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
423
424     // Request relayout
425     mImpl->RequestRelayout();
426   }
427 }
428
429 Text::LineWrap::Mode Controller::GetLineWrapMode() const
430 {
431   return mImpl->mModel->mLineWrapMode;
432 }
433
434 void Controller::SetTextElideEnabled( bool enabled )
435 {
436   mImpl->mModel->mElideEnabled = enabled;
437 }
438
439 bool Controller::IsTextElideEnabled() const
440 {
441   return mImpl->mModel->mElideEnabled;
442 }
443
444 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
445 {
446   mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
447   mImpl->mEventData->mPlaceholderEllipsisFlag = true;
448
449   // Update placeholder if there is no text
450   if( mImpl->IsShowingPlaceholderText() ||
451       ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
452   {
453     ShowPlaceholderText();
454   }
455 }
456
457 bool Controller::IsPlaceholderTextElideEnabled() const
458 {
459   return mImpl->mEventData->mIsPlaceholderElideEnabled;
460 }
461
462 void Controller::SetSelectionEnabled( bool enabled )
463 {
464   mImpl->mEventData->mSelectionEnabled = enabled;
465 }
466
467 bool Controller::IsSelectionEnabled() const
468 {
469   return mImpl->mEventData->mSelectionEnabled;
470 }
471
472 // public : Update
473
474 void Controller::SetText( const std::string& text )
475 {
476   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
477
478   // Reset keyboard as text changed
479   mImpl->ResetImfManager();
480
481   // Remove the previously set text and style.
482   ResetText();
483
484   // Remove the style.
485   ClearStyleData();
486
487   CharacterIndex lastCursorIndex = 0u;
488
489   if( NULL != mImpl->mEventData )
490   {
491     // If popup shown then hide it by switching to Editing state
492     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
493         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
494         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
495         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
496     {
497       mImpl->ChangeState( EventData::EDITING );
498     }
499   }
500
501   if( !text.empty() )
502   {
503     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
504
505     MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
506                                          mImpl->mModel->mLogicalModel->mFontDescriptionRuns );
507
508     Length textSize = 0u;
509     const uint8_t* utf8 = NULL;
510     if( mImpl->mMarkupProcessorEnabled )
511     {
512       ProcessMarkupString( text, markupProcessData );
513       textSize = markupProcessData.markupProcessedText.size();
514
515       // This is a bit horrible but std::string returns a (signed) char*
516       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
517     }
518     else
519     {
520       textSize = text.size();
521
522       // This is a bit horrible but std::string returns a (signed) char*
523       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
524     }
525
526     //  Convert text into UTF-32
527     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
528     utf32Characters.Resize( textSize );
529
530     // Transform a text array encoded in utf8 into an array encoded in utf32.
531     // It returns the actual number of characters.
532     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
533     utf32Characters.Resize( characterCount );
534
535     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
536     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
537
538     // The characters to be added.
539     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
540
541     // To reset the cursor position
542     lastCursorIndex = characterCount;
543
544     // Update the rest of the model during size negotiation
545     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
546
547     // The natural size needs to be re-calculated.
548     mImpl->mRecalculateNaturalSize = true;
549
550     // Apply modifications to the model
551     mImpl->mOperationsPending = ALL_OPERATIONS;
552   }
553   else
554   {
555     ShowPlaceholderText();
556   }
557
558   // Resets the cursor position.
559   ResetCursorPosition( lastCursorIndex );
560
561   // Scrolls the text to make the cursor visible.
562   ResetScrollPosition();
563
564   mImpl->RequestRelayout();
565
566   if( NULL != mImpl->mEventData )
567   {
568     // Cancel previously queued events
569     mImpl->mEventData->mEventQueue.clear();
570   }
571
572   // Do this last since it provides callbacks into application code.
573   if( NULL != mImpl->mEditableControlInterface )
574   {
575     mImpl->mEditableControlInterface->TextChanged();
576   }
577 }
578
579 void Controller::GetText( std::string& text ) const
580 {
581   if( !mImpl->IsShowingPlaceholderText() )
582   {
583     // Retrieves the text string.
584     mImpl->GetText( 0u, text );
585   }
586   else
587   {
588     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
589   }
590 }
591
592 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
593 {
594   if( NULL != mImpl->mEventData )
595   {
596     if( PLACEHOLDER_TYPE_INACTIVE == type )
597     {
598       mImpl->mEventData->mPlaceholderTextInactive = text;
599     }
600     else
601     {
602       mImpl->mEventData->mPlaceholderTextActive = text;
603     }
604
605     // Update placeholder if there is no text
606     if( mImpl->IsShowingPlaceholderText() ||
607         ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
608     {
609       ShowPlaceholderText();
610     }
611   }
612 }
613
614 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
615 {
616   if( NULL != mImpl->mEventData )
617   {
618     if( PLACEHOLDER_TYPE_INACTIVE == type )
619     {
620       text = mImpl->mEventData->mPlaceholderTextInactive;
621     }
622     else
623     {
624       text = mImpl->mEventData->mPlaceholderTextActive;
625     }
626   }
627 }
628
629 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
630 {
631   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
632
633   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
634   {
635     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
636     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
637
638     ClearFontData();
639
640     mImpl->RequestRelayout();
641   }
642 }
643
644 // public : Default style & Input style
645
646 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
647 {
648   if( NULL == mImpl->mFontDefaults )
649   {
650     mImpl->mFontDefaults = new FontDefaults();
651   }
652
653   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
654   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
655   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
656
657   // Clear the font-specific data
658   ClearFontData();
659
660   mImpl->RequestRelayout();
661 }
662
663 const std::string& Controller::GetDefaultFontFamily() const
664 {
665   if( NULL != mImpl->mFontDefaults )
666   {
667     return mImpl->mFontDefaults->mFontDescription.family;
668   }
669
670   return EMPTY_STRING;
671 }
672
673 void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
674 {
675   if( NULL != mImpl->mEventData )
676   {
677     if( NULL == mImpl->mEventData->mPlaceholderFont )
678     {
679       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
680     }
681
682     mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
683     DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
684     mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
685
686     mImpl->RequestRelayout();
687   }
688 }
689
690 const std::string& Controller::GetPlaceholderFontFamily() const
691 {
692   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
693   {
694     return mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
695   }
696
697   return EMPTY_STRING;
698 }
699
700 void Controller::SetDefaultFontWeight( FontWeight weight )
701 {
702   if( NULL == mImpl->mFontDefaults )
703   {
704     mImpl->mFontDefaults = new FontDefaults();
705   }
706
707   mImpl->mFontDefaults->mFontDescription.weight = weight;
708   mImpl->mFontDefaults->weightDefined = true;
709
710   // Clear the font-specific data
711   ClearFontData();
712
713   mImpl->RequestRelayout();
714 }
715
716 bool Controller::IsDefaultFontWeightDefined() const
717 {
718   if( NULL != mImpl->mFontDefaults )
719   {
720     return mImpl->mFontDefaults->weightDefined;
721   }
722
723   return false;
724 }
725
726 FontWeight Controller::GetDefaultFontWeight() const
727 {
728   if( NULL != mImpl->mFontDefaults )
729   {
730     return mImpl->mFontDefaults->mFontDescription.weight;
731   }
732
733   return TextAbstraction::FontWeight::NORMAL;
734 }
735
736 void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
737 {
738   if( NULL != mImpl->mEventData )
739   {
740     if( NULL == mImpl->mEventData->mPlaceholderFont )
741     {
742       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
743     }
744
745     mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
746     mImpl->mEventData->mPlaceholderFont->weightDefined = true;
747
748     mImpl->RequestRelayout();
749   }
750 }
751
752 bool Controller::IsPlaceholderTextFontWeightDefined() const
753 {
754   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
755   {
756     return mImpl->mEventData->mPlaceholderFont->weightDefined;
757   }
758   return false;
759 }
760
761 FontWeight Controller::GetPlaceholderTextFontWeight() const
762 {
763   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
764   {
765     return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
766   }
767
768   return TextAbstraction::FontWeight::NORMAL;
769 }
770
771 void Controller::SetDefaultFontWidth( FontWidth width )
772 {
773   if( NULL == mImpl->mFontDefaults )
774   {
775     mImpl->mFontDefaults = new FontDefaults();
776   }
777
778   mImpl->mFontDefaults->mFontDescription.width = width;
779   mImpl->mFontDefaults->widthDefined = true;
780
781   // Clear the font-specific data
782   ClearFontData();
783
784   mImpl->RequestRelayout();
785 }
786
787 bool Controller::IsDefaultFontWidthDefined() const
788 {
789   if( NULL != mImpl->mFontDefaults )
790   {
791     return mImpl->mFontDefaults->widthDefined;
792   }
793
794   return false;
795 }
796
797 FontWidth Controller::GetDefaultFontWidth() const
798 {
799   if( NULL != mImpl->mFontDefaults )
800   {
801     return mImpl->mFontDefaults->mFontDescription.width;
802   }
803
804   return TextAbstraction::FontWidth::NORMAL;
805 }
806
807 void Controller::SetPlaceholderTextFontWidth( FontWidth width )
808 {
809   if( NULL != mImpl->mEventData )
810   {
811     if( NULL == mImpl->mEventData->mPlaceholderFont )
812     {
813       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
814     }
815
816     mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
817     mImpl->mEventData->mPlaceholderFont->widthDefined = true;
818
819     mImpl->RequestRelayout();
820   }
821 }
822
823 bool Controller::IsPlaceholderTextFontWidthDefined() const
824 {
825   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
826   {
827     return mImpl->mEventData->mPlaceholderFont->widthDefined;
828   }
829   return false;
830 }
831
832 FontWidth Controller::GetPlaceholderTextFontWidth() const
833 {
834   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
835   {
836     return mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
837   }
838
839   return TextAbstraction::FontWidth::NORMAL;
840 }
841
842 void Controller::SetDefaultFontSlant( FontSlant slant )
843 {
844   if( NULL == mImpl->mFontDefaults )
845   {
846     mImpl->mFontDefaults = new FontDefaults();
847   }
848
849   mImpl->mFontDefaults->mFontDescription.slant = slant;
850   mImpl->mFontDefaults->slantDefined = true;
851
852   // Clear the font-specific data
853   ClearFontData();
854
855   mImpl->RequestRelayout();
856 }
857
858 bool Controller::IsDefaultFontSlantDefined() const
859 {
860   if( NULL != mImpl->mFontDefaults )
861   {
862     return mImpl->mFontDefaults->slantDefined;
863   }
864   return false;
865 }
866
867 FontSlant Controller::GetDefaultFontSlant() const
868 {
869   if( NULL != mImpl->mFontDefaults )
870   {
871     return mImpl->mFontDefaults->mFontDescription.slant;
872   }
873
874   return TextAbstraction::FontSlant::NORMAL;
875 }
876
877 void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
878 {
879   if( NULL != mImpl->mEventData )
880   {
881     if( NULL == mImpl->mEventData->mPlaceholderFont )
882     {
883       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
884     }
885
886     mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
887     mImpl->mEventData->mPlaceholderFont->slantDefined = true;
888
889     mImpl->RequestRelayout();
890   }
891 }
892
893 bool Controller::IsPlaceholderTextFontSlantDefined() const
894 {
895   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
896   {
897     return mImpl->mEventData->mPlaceholderFont->slantDefined;
898   }
899   return false;
900 }
901
902 FontSlant Controller::GetPlaceholderTextFontSlant() const
903 {
904   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
905   {
906     return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
907   }
908
909   return TextAbstraction::FontSlant::NORMAL;
910 }
911
912 void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
913 {
914   if( NULL == mImpl->mFontDefaults )
915   {
916     mImpl->mFontDefaults = new FontDefaults();
917   }
918
919   switch( type )
920   {
921     case POINT_SIZE:
922     {
923       mImpl->mFontDefaults->mDefaultPointSize = fontSize;
924       mImpl->mFontDefaults->sizeDefined = true;
925       break;
926     }
927     case PIXEL_SIZE:
928     {
929       // Point size = Pixel size * 72.f / DPI
930       unsigned int horizontalDpi = 0u;
931       unsigned int verticalDpi = 0u;
932       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
933       fontClient.GetDpi( horizontalDpi, verticalDpi );
934
935       mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
936       mImpl->mFontDefaults->sizeDefined = true;
937       break;
938     }
939   }
940
941   // Clear the font-specific data
942   ClearFontData();
943
944   mImpl->RequestRelayout();
945 }
946
947 float Controller::GetDefaultFontSize( FontSizeType type ) const
948 {
949   float value = 0.0f;
950   if( NULL != mImpl->mFontDefaults )
951   {
952     switch( type )
953     {
954       case POINT_SIZE:
955       {
956         value = mImpl->mFontDefaults->mDefaultPointSize;
957         break;
958       }
959       case PIXEL_SIZE:
960       {
961         // Pixel size = Point size * DPI / 72.f
962         unsigned int horizontalDpi = 0u;
963         unsigned int verticalDpi = 0u;
964         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
965         fontClient.GetDpi( horizontalDpi, verticalDpi );
966
967         value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
968         break;
969       }
970     }
971     return value;
972   }
973
974   return value;
975 }
976
977 void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
978 {
979   if( NULL != mImpl->mEventData )
980   {
981     if( NULL == mImpl->mEventData->mPlaceholderFont )
982     {
983       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
984     }
985
986     switch( type )
987     {
988       case POINT_SIZE:
989       {
990         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
991         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
992         mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
993         break;
994       }
995       case PIXEL_SIZE:
996       {
997         // Point size = Pixel size * 72.f / DPI
998         unsigned int horizontalDpi = 0u;
999         unsigned int verticalDpi = 0u;
1000         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1001         fontClient.GetDpi( horizontalDpi, verticalDpi );
1002
1003         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
1004         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
1005         mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
1006         break;
1007       }
1008     }
1009
1010     mImpl->RequestRelayout();
1011   }
1012 }
1013
1014 float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
1015 {
1016   float value = 0.0f;
1017   if( NULL != mImpl->mEventData )
1018   {
1019     switch( type )
1020     {
1021       case POINT_SIZE:
1022       {
1023         if( NULL != mImpl->mEventData->mPlaceholderFont )
1024         {
1025           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
1026         }
1027         else
1028         {
1029           // If the placeholder text font size is not set, then return the default font size.
1030           value = GetDefaultFontSize( POINT_SIZE );
1031         }
1032         break;
1033       }
1034       case PIXEL_SIZE:
1035       {
1036         if( NULL != mImpl->mEventData->mPlaceholderFont )
1037         {
1038           // Pixel size = Point size * DPI / 72.f
1039           unsigned int horizontalDpi = 0u;
1040           unsigned int verticalDpi = 0u;
1041           TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1042           fontClient.GetDpi( horizontalDpi, verticalDpi );
1043
1044           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1045         }
1046         else
1047         {
1048           // If the placeholder text font size is not set, then return the default font size.
1049           value = GetDefaultFontSize( PIXEL_SIZE );
1050         }
1051         break;
1052       }
1053     }
1054     return value;
1055   }
1056
1057   return value;
1058 }
1059
1060 void Controller::SetDefaultColor( const Vector4& color )
1061 {
1062   mImpl->mTextColor = color;
1063
1064   if( !mImpl->IsShowingPlaceholderText() )
1065   {
1066     mImpl->mModel->mVisualModel->SetTextColor( color );
1067
1068     mImpl->RequestRelayout();
1069   }
1070 }
1071
1072 const Vector4& Controller::GetDefaultColor() const
1073 {
1074   return mImpl->mTextColor;
1075 }
1076
1077 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
1078 {
1079   if( NULL != mImpl->mEventData )
1080   {
1081     mImpl->mEventData->mPlaceholderTextColor = textColor;
1082   }
1083
1084   if( mImpl->IsShowingPlaceholderText() )
1085   {
1086     mImpl->mModel->mVisualModel->SetTextColor( textColor );
1087     mImpl->RequestRelayout();
1088   }
1089 }
1090
1091 const Vector4& Controller::GetPlaceholderTextColor() const
1092 {
1093   if( NULL != mImpl->mEventData )
1094   {
1095     return mImpl->mEventData->mPlaceholderTextColor;
1096   }
1097
1098   return Color::BLACK;
1099 }
1100
1101 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1102 {
1103   mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
1104
1105   mImpl->RequestRelayout();
1106 }
1107
1108 const Vector2& Controller::GetShadowOffset() const
1109 {
1110   return mImpl->mModel->mVisualModel->GetShadowOffset();
1111 }
1112
1113 void Controller::SetShadowColor( const Vector4& shadowColor )
1114 {
1115   mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
1116
1117   mImpl->RequestRelayout();
1118 }
1119
1120 const Vector4& Controller::GetShadowColor() const
1121 {
1122   return mImpl->mModel->mVisualModel->GetShadowColor();
1123 }
1124
1125 void Controller::SetShadowBlurRadius( const float& shadowBlurRadius )
1126 {
1127   if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 )
1128   {
1129     mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius );
1130
1131     mImpl->RequestRelayout();
1132   }
1133 }
1134
1135 const float& Controller::GetShadowBlurRadius() const
1136 {
1137   return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1138 }
1139
1140 void Controller::SetUnderlineColor( const Vector4& color )
1141 {
1142   mImpl->mModel->mVisualModel->SetUnderlineColor( color );
1143
1144   mImpl->RequestRelayout();
1145 }
1146
1147 const Vector4& Controller::GetUnderlineColor() const
1148 {
1149   return mImpl->mModel->mVisualModel->GetUnderlineColor();
1150 }
1151
1152 void Controller::SetUnderlineEnabled( bool enabled )
1153 {
1154   mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
1155
1156   mImpl->RequestRelayout();
1157 }
1158
1159 bool Controller::IsUnderlineEnabled() const
1160 {
1161   return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1162 }
1163
1164 void Controller::SetUnderlineHeight( float height )
1165 {
1166   mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
1167
1168   mImpl->RequestRelayout();
1169 }
1170
1171 float Controller::GetUnderlineHeight() const
1172 {
1173   return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1174 }
1175
1176 void Controller::SetOutlineColor( const Vector4& color )
1177 {
1178   mImpl->mModel->mVisualModel->SetOutlineColor( color );
1179
1180   mImpl->RequestRelayout();
1181 }
1182
1183 const Vector4& Controller::GetOutlineColor() const
1184 {
1185   return mImpl->mModel->mVisualModel->GetOutlineColor();
1186 }
1187
1188 void Controller::SetOutlineWidth( float width )
1189 {
1190   mImpl->mModel->mVisualModel->SetOutlineWidth( width );
1191
1192   mImpl->RequestRelayout();
1193 }
1194
1195 float Controller::GetOutlineWidth() const
1196 {
1197   return mImpl->mModel->mVisualModel->GetOutlineWidth();
1198 }
1199
1200 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
1201 {
1202   if( NULL == mImpl->mEmbossDefaults )
1203   {
1204     mImpl->mEmbossDefaults = new EmbossDefaults();
1205   }
1206
1207   mImpl->mEmbossDefaults->properties = embossProperties;
1208 }
1209
1210 const std::string& Controller::GetDefaultEmbossProperties() const
1211 {
1212   if( NULL != mImpl->mEmbossDefaults )
1213   {
1214     return mImpl->mEmbossDefaults->properties;
1215   }
1216
1217   return EMPTY_STRING;
1218 }
1219
1220 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
1221 {
1222   if( NULL == mImpl->mOutlineDefaults )
1223   {
1224     mImpl->mOutlineDefaults = new OutlineDefaults();
1225   }
1226
1227   mImpl->mOutlineDefaults->properties = outlineProperties;
1228 }
1229
1230 const std::string& Controller::GetDefaultOutlineProperties() const
1231 {
1232   if( NULL != mImpl->mOutlineDefaults )
1233   {
1234     return mImpl->mOutlineDefaults->properties;
1235   }
1236
1237   return EMPTY_STRING;
1238 }
1239
1240 void Controller::SetDefaultLineSpacing( float lineSpacing )
1241 {
1242   //TODO finish implementation
1243   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
1244 }
1245
1246 float Controller::GetDefaultLineSpacing() const
1247 {
1248   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1249 }
1250
1251 void Controller::SetInputColor( const Vector4& color )
1252 {
1253   if( NULL != mImpl->mEventData )
1254   {
1255     mImpl->mEventData->mInputStyle.textColor = color;
1256     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1257
1258     if( EventData::SELECTING == mImpl->mEventData->mState )
1259     {
1260       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1261
1262       // Get start and end position of selection
1263       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1264       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1265
1266       // Add the color run.
1267       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1268       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1269
1270       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1271       colorRun.color = color;
1272       colorRun.characterRun.characterIndex = startOfSelectedText;
1273       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1274
1275       // Request to relayout.
1276       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1277       mImpl->RequestRelayout();
1278
1279       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1280       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1281       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1282     }
1283   }
1284 }
1285
1286 const Vector4& Controller::GetInputColor() const
1287 {
1288   if( NULL != mImpl->mEventData )
1289   {
1290     return mImpl->mEventData->mInputStyle.textColor;
1291   }
1292
1293   // Return the default text's color if there is no EventData.
1294   return mImpl->mTextColor;
1295
1296 }
1297
1298 void Controller::SetInputFontFamily( const std::string& fontFamily )
1299 {
1300   if( NULL != mImpl->mEventData )
1301   {
1302     mImpl->mEventData->mInputStyle.familyName = fontFamily;
1303     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
1304
1305     if( EventData::SELECTING == mImpl->mEventData->mState )
1306     {
1307       CharacterIndex startOfSelectedText = 0u;
1308       Length lengthOfSelectedText = 0u;
1309       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1310                                                                             mImpl->mModel->mLogicalModel,
1311                                                                             startOfSelectedText,
1312                                                                             lengthOfSelectedText );
1313
1314       fontDescriptionRun.familyLength = fontFamily.size();
1315       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
1316       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
1317       fontDescriptionRun.familyDefined = true;
1318
1319       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
1320
1321       // Request to relayout.
1322       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1323                                                                VALIDATE_FONTS            |
1324                                                                SHAPE_TEXT                |
1325                                                                GET_GLYPH_METRICS         |
1326                                                                LAYOUT                    |
1327                                                                UPDATE_LAYOUT_SIZE        |
1328                                                                REORDER                   |
1329                                                                ALIGN );
1330       mImpl->mRecalculateNaturalSize = true;
1331       mImpl->RequestRelayout();
1332
1333       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1334       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1335       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1336
1337       // As the font changes, recalculate the handle positions is needed.
1338       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1339       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1340       mImpl->mEventData->mUpdateHighlightBox = true;
1341       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1342     }
1343   }
1344 }
1345
1346 const std::string& Controller::GetInputFontFamily() const
1347 {
1348   if( NULL != mImpl->mEventData )
1349   {
1350     return mImpl->mEventData->mInputStyle.familyName;
1351   }
1352
1353   // Return the default font's family if there is no EventData.
1354   return GetDefaultFontFamily();
1355 }
1356
1357 void Controller::SetInputFontWeight( FontWeight weight )
1358 {
1359   if( NULL != mImpl->mEventData )
1360   {
1361     mImpl->mEventData->mInputStyle.weight = weight;
1362     mImpl->mEventData->mInputStyle.isWeightDefined = true;
1363
1364     if( EventData::SELECTING == mImpl->mEventData->mState )
1365     {
1366       CharacterIndex startOfSelectedText = 0u;
1367       Length lengthOfSelectedText = 0u;
1368       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1369                                                                             mImpl->mModel->mLogicalModel,
1370                                                                             startOfSelectedText,
1371                                                                             lengthOfSelectedText );
1372
1373       fontDescriptionRun.weight = weight;
1374       fontDescriptionRun.weightDefined = true;
1375
1376       // Request to relayout.
1377       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1378                                                                VALIDATE_FONTS            |
1379                                                                SHAPE_TEXT                |
1380                                                                GET_GLYPH_METRICS         |
1381                                                                LAYOUT                    |
1382                                                                UPDATE_LAYOUT_SIZE        |
1383                                                                REORDER                   |
1384                                                                ALIGN );
1385       mImpl->mRecalculateNaturalSize = true;
1386       mImpl->RequestRelayout();
1387
1388       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1389       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1390       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1391
1392       // As the font might change, recalculate the handle positions is needed.
1393       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1394       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1395       mImpl->mEventData->mUpdateHighlightBox = true;
1396       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1397     }
1398   }
1399 }
1400
1401 bool Controller::IsInputFontWeightDefined() const
1402 {
1403   bool defined = false;
1404
1405   if( NULL != mImpl->mEventData )
1406   {
1407     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1408   }
1409
1410   return defined;
1411 }
1412
1413 FontWeight Controller::GetInputFontWeight() const
1414 {
1415   if( NULL != mImpl->mEventData )
1416   {
1417     return mImpl->mEventData->mInputStyle.weight;
1418   }
1419
1420   return GetDefaultFontWeight();
1421 }
1422
1423 void Controller::SetInputFontWidth( FontWidth width )
1424 {
1425   if( NULL != mImpl->mEventData )
1426   {
1427     mImpl->mEventData->mInputStyle.width = width;
1428     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1429
1430     if( EventData::SELECTING == mImpl->mEventData->mState )
1431     {
1432       CharacterIndex startOfSelectedText = 0u;
1433       Length lengthOfSelectedText = 0u;
1434       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1435                                                                             mImpl->mModel->mLogicalModel,
1436                                                                             startOfSelectedText,
1437                                                                             lengthOfSelectedText );
1438
1439       fontDescriptionRun.width = width;
1440       fontDescriptionRun.widthDefined = true;
1441
1442       // Request to relayout.
1443       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1444                                                                VALIDATE_FONTS            |
1445                                                                SHAPE_TEXT                |
1446                                                                GET_GLYPH_METRICS         |
1447                                                                LAYOUT                    |
1448                                                                UPDATE_LAYOUT_SIZE        |
1449                                                                REORDER                   |
1450                                                                ALIGN );
1451       mImpl->mRecalculateNaturalSize = true;
1452       mImpl->RequestRelayout();
1453
1454       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1455       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1456       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1457
1458       // As the font might change, recalculate the handle positions is needed.
1459       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1460       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1461       mImpl->mEventData->mUpdateHighlightBox = true;
1462       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1463     }
1464   }
1465 }
1466
1467 bool Controller::IsInputFontWidthDefined() const
1468 {
1469   bool defined = false;
1470
1471   if( NULL != mImpl->mEventData )
1472   {
1473     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1474   }
1475
1476   return defined;
1477 }
1478
1479 FontWidth Controller::GetInputFontWidth() const
1480 {
1481   if( NULL != mImpl->mEventData )
1482   {
1483     return mImpl->mEventData->mInputStyle.width;
1484   }
1485
1486   return GetDefaultFontWidth();
1487 }
1488
1489 void Controller::SetInputFontSlant( FontSlant slant )
1490 {
1491   if( NULL != mImpl->mEventData )
1492   {
1493     mImpl->mEventData->mInputStyle.slant = slant;
1494     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1495
1496     if( EventData::SELECTING == mImpl->mEventData->mState )
1497     {
1498       CharacterIndex startOfSelectedText = 0u;
1499       Length lengthOfSelectedText = 0u;
1500       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1501                                                                             mImpl->mModel->mLogicalModel,
1502                                                                             startOfSelectedText,
1503                                                                             lengthOfSelectedText );
1504
1505       fontDescriptionRun.slant = slant;
1506       fontDescriptionRun.slantDefined = true;
1507
1508       // Request to relayout.
1509       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1510                                                                VALIDATE_FONTS            |
1511                                                                SHAPE_TEXT                |
1512                                                                GET_GLYPH_METRICS         |
1513                                                                LAYOUT                    |
1514                                                                UPDATE_LAYOUT_SIZE        |
1515                                                                REORDER                   |
1516                                                                ALIGN );
1517       mImpl->mRecalculateNaturalSize = true;
1518       mImpl->RequestRelayout();
1519
1520       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1521       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1522       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1523
1524       // As the font might change, recalculate the handle positions is needed.
1525       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1526       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1527       mImpl->mEventData->mUpdateHighlightBox = true;
1528       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1529     }
1530   }
1531 }
1532
1533 bool Controller::IsInputFontSlantDefined() const
1534 {
1535   bool defined = false;
1536
1537   if( NULL != mImpl->mEventData )
1538   {
1539     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1540   }
1541
1542   return defined;
1543 }
1544
1545 FontSlant Controller::GetInputFontSlant() const
1546 {
1547   if( NULL != mImpl->mEventData )
1548   {
1549     return mImpl->mEventData->mInputStyle.slant;
1550   }
1551
1552   return GetDefaultFontSlant();
1553 }
1554
1555 void Controller::SetInputFontPointSize( float size )
1556 {
1557   if( NULL != mImpl->mEventData )
1558   {
1559     mImpl->mEventData->mInputStyle.size = size;
1560     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1561
1562     if( EventData::SELECTING == mImpl->mEventData->mState )
1563     {
1564       CharacterIndex startOfSelectedText = 0u;
1565       Length lengthOfSelectedText = 0u;
1566       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1567                                                                             mImpl->mModel->mLogicalModel,
1568                                                                             startOfSelectedText,
1569                                                                             lengthOfSelectedText );
1570
1571       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1572       fontDescriptionRun.sizeDefined = true;
1573
1574       // Request to relayout.
1575       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1576                                                                VALIDATE_FONTS            |
1577                                                                SHAPE_TEXT                |
1578                                                                GET_GLYPH_METRICS         |
1579                                                                LAYOUT                    |
1580                                                                UPDATE_LAYOUT_SIZE        |
1581                                                                REORDER                   |
1582                                                                ALIGN );
1583       mImpl->mRecalculateNaturalSize = true;
1584       mImpl->RequestRelayout();
1585
1586       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1587       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1588       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1589
1590       // As the font might change, recalculate the handle positions is needed.
1591       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1592       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1593       mImpl->mEventData->mUpdateHighlightBox = true;
1594       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1595     }
1596   }
1597 }
1598
1599 float Controller::GetInputFontPointSize() const
1600 {
1601   if( NULL != mImpl->mEventData )
1602   {
1603     return mImpl->mEventData->mInputStyle.size;
1604   }
1605
1606   // Return the default font's point size if there is no EventData.
1607   return GetDefaultFontSize( Text::Controller::POINT_SIZE );
1608 }
1609
1610 void Controller::SetInputLineSpacing( float lineSpacing )
1611 {
1612   if( NULL != mImpl->mEventData )
1613   {
1614     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1615     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1616   }
1617 }
1618
1619 float Controller::GetInputLineSpacing() const
1620 {
1621   if( NULL != mImpl->mEventData )
1622   {
1623     return mImpl->mEventData->mInputStyle.lineSpacing;
1624   }
1625
1626   return 0.f;
1627 }
1628
1629 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1630 {
1631   if( NULL != mImpl->mEventData )
1632   {
1633     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1634   }
1635 }
1636
1637 const std::string& Controller::GetInputShadowProperties() const
1638 {
1639   if( NULL != mImpl->mEventData )
1640   {
1641     return mImpl->mEventData->mInputStyle.shadowProperties;
1642   }
1643
1644   return EMPTY_STRING;
1645 }
1646
1647 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1648 {
1649   if( NULL != mImpl->mEventData )
1650   {
1651     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1652   }
1653 }
1654
1655 const std::string& Controller::GetInputUnderlineProperties() const
1656 {
1657   if( NULL != mImpl->mEventData )
1658   {
1659     return mImpl->mEventData->mInputStyle.underlineProperties;
1660   }
1661
1662   return EMPTY_STRING;
1663 }
1664
1665 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1666 {
1667   if( NULL != mImpl->mEventData )
1668   {
1669     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1670   }
1671 }
1672
1673 const std::string& Controller::GetInputEmbossProperties() const
1674 {
1675   if( NULL != mImpl->mEventData )
1676   {
1677     return mImpl->mEventData->mInputStyle.embossProperties;
1678   }
1679
1680   return GetDefaultEmbossProperties();
1681 }
1682
1683 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1684 {
1685   if( NULL != mImpl->mEventData )
1686   {
1687     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1688   }
1689 }
1690
1691 const std::string& Controller::GetInputOutlineProperties() const
1692 {
1693   if( NULL != mImpl->mEventData )
1694   {
1695     return mImpl->mEventData->mInputStyle.outlineProperties;
1696   }
1697
1698   return GetDefaultOutlineProperties();
1699 }
1700
1701 void Controller::SetInputModePassword( bool passwordInput )
1702 {
1703   if( NULL != mImpl->mEventData )
1704   {
1705     mImpl->mEventData->mPasswordInput = passwordInput;
1706   }
1707 }
1708
1709 bool Controller::IsInputModePassword()
1710 {
1711   if( NULL != mImpl->mEventData )
1712   {
1713     return mImpl->mEventData->mPasswordInput;
1714   }
1715   return false;
1716 }
1717
1718 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1719 {
1720   if( NULL != mImpl->mEventData )
1721   {
1722     mImpl->mEventData->mDoubleTapAction = action;
1723   }
1724 }
1725
1726 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1727 {
1728   NoTextTap::Action action = NoTextTap::NO_ACTION;
1729
1730   if( NULL != mImpl->mEventData )
1731   {
1732     action = mImpl->mEventData->mDoubleTapAction;
1733   }
1734
1735   return action;
1736 }
1737
1738 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1739 {
1740   if( NULL != mImpl->mEventData )
1741   {
1742     mImpl->mEventData->mLongPressAction = action;
1743   }
1744 }
1745
1746 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1747 {
1748   NoTextTap::Action action = NoTextTap::NO_ACTION;
1749
1750   if( NULL != mImpl->mEventData )
1751   {
1752     action = mImpl->mEventData->mLongPressAction;
1753   }
1754
1755   return action;
1756 }
1757
1758 bool Controller::IsUnderlineSetByString()
1759 {
1760   return mImpl->mUnderlineSetByString;
1761 }
1762
1763 void Controller::UnderlineSetByString( bool setByString )
1764 {
1765   mImpl->mUnderlineSetByString = setByString;
1766 }
1767
1768 bool Controller::IsShadowSetByString()
1769 {
1770   return mImpl->mShadowSetByString;
1771 }
1772
1773 void Controller::ShadowSetByString( bool setByString )
1774 {
1775   mImpl->mShadowSetByString = setByString;
1776 }
1777
1778 bool Controller::IsOutlineSetByString()
1779 {
1780   return mImpl->mOutlineSetByString;
1781 }
1782
1783 void Controller::OutlineSetByString( bool setByString )
1784 {
1785   mImpl->mOutlineSetByString = setByString;
1786 }
1787
1788 bool Controller::IsFontStyleSetByString()
1789 {
1790   return mImpl->mFontStyleSetByString;
1791 }
1792
1793 void Controller::FontStyleSetByString( bool setByString )
1794 {
1795   mImpl->mFontStyleSetByString = setByString;
1796 }
1797
1798 // public : Queries & retrieves.
1799
1800 Layout::Engine& Controller::GetLayoutEngine()
1801 {
1802   return mImpl->mLayoutEngine;
1803 }
1804
1805 View& Controller::GetView()
1806 {
1807   return mImpl->mView;
1808 }
1809
1810 Vector3 Controller::GetNaturalSize()
1811 {
1812   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1813   Vector3 naturalSize;
1814
1815   // Make sure the model is up-to-date before layouting
1816   ProcessModifyEvents();
1817
1818   if( mImpl->mRecalculateNaturalSize )
1819   {
1820     // Operations that can be done only once until the text changes.
1821     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1822                                                                            GET_SCRIPTS       |
1823                                                                            VALIDATE_FONTS    |
1824                                                                            GET_LINE_BREAKS   |
1825                                                                            GET_WORD_BREAKS   |
1826                                                                            BIDI_INFO         |
1827                                                                            SHAPE_TEXT        |
1828                                                                            GET_GLYPH_METRICS );
1829
1830     // Set the update info to relayout the whole text.
1831     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1832     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1833
1834     // Make sure the model is up-to-date before layouting
1835     mImpl->UpdateModel( onlyOnceOperations );
1836
1837     // Layout the text for the new width.
1838     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
1839
1840     // Store the actual control's size to restore later.
1841     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1842
1843     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1844                 static_cast<OperationsMask>( onlyOnceOperations |
1845                                              LAYOUT | REORDER ),
1846                 naturalSize.GetVectorXY() );
1847
1848     // Do not do again the only once operations.
1849     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1850
1851     // Do the size related operations again.
1852     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1853                                                                         ALIGN  |
1854                                                                         REORDER );
1855     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1856
1857     // Stores the natural size to avoid recalculate it again
1858     // unless the text/style changes.
1859     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1860
1861     mImpl->mRecalculateNaturalSize = false;
1862
1863     // Clear the update info. This info will be set the next time the text is updated.
1864     mImpl->mTextUpdateInfo.Clear();
1865
1866     // Restore the actual control's size.
1867     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1868
1869     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1870   }
1871   else
1872   {
1873     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1874
1875     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1876   }
1877
1878   naturalSize.x = ConvertToEven( naturalSize.x );
1879   naturalSize.y = ConvertToEven( naturalSize.y );
1880
1881   return naturalSize;
1882 }
1883
1884 float Controller::GetHeightForWidth( float width )
1885 {
1886   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1887   // Make sure the model is up-to-date before layouting
1888   ProcessModifyEvents();
1889
1890   Size layoutSize;
1891   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
1892                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1893                                                          mImpl->mTextUpdateInfo.mClearAll            )
1894   {
1895     // Operations that can be done only once until the text changes.
1896     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1897                                                                            GET_SCRIPTS       |
1898                                                                            VALIDATE_FONTS    |
1899                                                                            GET_LINE_BREAKS   |
1900                                                                            GET_WORD_BREAKS   |
1901                                                                            BIDI_INFO         |
1902                                                                            SHAPE_TEXT        |
1903                                                                            GET_GLYPH_METRICS );
1904
1905     // Set the update info to relayout the whole text.
1906     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1907     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1908
1909     // Make sure the model is up-to-date before layouting
1910     mImpl->UpdateModel( onlyOnceOperations );
1911
1912
1913     // Layout the text for the new width.
1914     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1915
1916     // Store the actual control's width.
1917     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1918
1919     DoRelayout( Size( width, MAX_FLOAT ),
1920                 static_cast<OperationsMask>( onlyOnceOperations |
1921                                              LAYOUT ),
1922                 layoutSize );
1923
1924     // Do not do again the only once operations.
1925     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1926
1927     // Do the size related operations again.
1928     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1929                                                                         ALIGN  |
1930                                                                         REORDER );
1931
1932     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1933
1934     // Clear the update info. This info will be set the next time the text is updated.
1935     mImpl->mTextUpdateInfo.Clear();
1936
1937     // Restore the actual control's width.
1938     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1939
1940     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1941   }
1942   else
1943   {
1944     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1945     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1946   }
1947
1948   return layoutSize.height;
1949 }
1950
1951 int Controller::GetLineCount( float width )
1952 {
1953   GetHeightForWidth( width );
1954   int numberofLines = mImpl->mModel->GetNumberOfLines();
1955   return numberofLines;
1956 }
1957
1958 const ModelInterface* const Controller::GetTextModel() const
1959 {
1960   return mImpl->mModel.Get();
1961 }
1962
1963 float Controller::GetScrollAmountByUserInput()
1964 {
1965   float scrollAmount = 0.0f;
1966
1967   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1968   {
1969     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1970     mImpl->mEventData->mCheckScrollAmount = false;
1971   }
1972   return scrollAmount;
1973 }
1974
1975 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1976 {
1977   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1978   bool isScrolled;
1979
1980   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1981   layoutHeight = layout.height;
1982   scrollPosition = mImpl->mModel->mScrollPosition.y;
1983   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1984   return isScrolled;
1985 }
1986
1987 void Controller::SetHiddenInputOption(const Property::Map& options )
1988 {
1989   if( NULL == mImpl->mHiddenInput )
1990   {
1991     mImpl->mHiddenInput = new HiddenText( this );
1992   }
1993   mImpl->mHiddenInput->SetProperties(options);
1994 }
1995
1996 void Controller::GetHiddenInputOption(Property::Map& options )
1997 {
1998   if( NULL != mImpl->mHiddenInput )
1999   {
2000     mImpl->mHiddenInput->GetProperties(options);
2001   }
2002 }
2003
2004 void Controller::SetPlaceholderProperty( const Property::Map& map )
2005 {
2006   const Property::Map::SizeType count = map.Count();
2007
2008   for( Property::Map::SizeType position = 0; position < count; ++position )
2009   {
2010     KeyValuePair keyValue = map.GetKeyValue( position );
2011     Property::Key& key = keyValue.first;
2012     Property::Value& value = keyValue.second;
2013
2014     if( key == Toolkit::Text::PlaceHolder::Property::TEXT  || key == PLACEHOLDER_TEXT )
2015     {
2016       std::string text = "";
2017       value.Get( text );
2018       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
2019     }
2020     else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
2021     {
2022       std::string text = "";
2023       value.Get( text );
2024       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
2025     }
2026     else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
2027     {
2028       Vector4 textColor;
2029       value.Get( textColor );
2030       if( GetPlaceholderTextColor() != textColor )
2031       {
2032         SetPlaceholderTextColor( textColor );
2033       }
2034     }
2035     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
2036     {
2037       std::string fontFamily = "";
2038       value.Get( fontFamily );
2039       SetPlaceholderFontFamily( fontFamily );
2040     }
2041     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
2042     {
2043       SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
2044     }
2045     else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
2046     {
2047       float pointSize;
2048       value.Get( pointSize );
2049       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
2050       {
2051         SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
2052       }
2053     }
2054     else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
2055     {
2056       float pixelSize;
2057       value.Get( pixelSize );
2058       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
2059       {
2060         SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
2061       }
2062     }
2063     else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
2064     {
2065       bool ellipsis;
2066       value.Get( ellipsis );
2067       SetPlaceholderTextElideEnabled( ellipsis );
2068     }
2069   }
2070 }
2071
2072 void Controller::GetPlaceholderProperty( Property::Map& map )
2073 {
2074   if( NULL != mImpl->mEventData )
2075   {
2076     if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
2077     {
2078       map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
2079     }
2080     if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
2081     {
2082       map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
2083     }
2084
2085     map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
2086     map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily();
2087
2088     Property::Value fontStyleMapGet;
2089     GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
2090     map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
2091
2092     // Choose font size : POINT_SIZE or PIXEL_SIZE
2093     if( !mImpl->mEventData->mIsPlaceholderPixelSize )
2094     {
2095       map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
2096     }
2097     else
2098     {
2099       map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
2100     }
2101
2102     if( mImpl->mEventData->mPlaceholderEllipsisFlag )
2103     {
2104       map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled();
2105     }
2106   }
2107 }
2108
2109 // public : Relayout.
2110
2111 Controller::UpdateTextType Controller::Relayout( const Size& size )
2112 {
2113   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2114
2115   UpdateTextType updateTextType = NONE_UPDATED;
2116
2117   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2118   {
2119     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2120     {
2121       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2122       updateTextType = MODEL_UPDATED;
2123     }
2124
2125     // Clear the update info. This info will be set the next time the text is updated.
2126     mImpl->mTextUpdateInfo.Clear();
2127
2128     // Not worth to relayout if width or height is equal to zero.
2129     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2130
2131     return updateTextType;
2132   }
2133
2134   // Whether a new size has been set.
2135   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2136
2137   if( newSize )
2138   {
2139     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2140
2141     // Layout operations that need to be done if the size changes.
2142     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2143                                                              LAYOUT                    |
2144                                                              ALIGN                     |
2145                                                              UPDATE_LAYOUT_SIZE        |
2146                                                              REORDER );
2147     // Set the update info to relayout the whole text.
2148     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2149     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2150
2151     // Store the size used to layout the text.
2152     mImpl->mModel->mVisualModel->mControlSize = size;
2153   }
2154
2155   // Whether there are modify events.
2156   if( 0u != mImpl->mModifyEvents.Count() )
2157   {
2158     // Style operations that need to be done if the text is modified.
2159     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2160                                                              COLOR );
2161   }
2162
2163   // Set the update info to elide the text.
2164   if( mImpl->mModel->mElideEnabled ||
2165       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2166   {
2167     // Update Text layout for applying elided
2168     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2169                                                              ALIGN                     |
2170                                                              LAYOUT                    |
2171                                                              UPDATE_LAYOUT_SIZE        |
2172                                                              REORDER );
2173     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2174     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2175   }
2176
2177   // Make sure the model is up-to-date before layouting.
2178   ProcessModifyEvents();
2179   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2180
2181   // Layout the text.
2182   Size layoutSize;
2183   updated = DoRelayout( size,
2184                         mImpl->mOperationsPending,
2185                         layoutSize ) || updated;
2186
2187   if( updated )
2188   {
2189     updateTextType = MODEL_UPDATED;
2190   }
2191
2192   // Do not re-do any operation until something changes.
2193   mImpl->mOperationsPending = NO_OPERATION;
2194   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2195
2196   // Whether the text control is editable
2197   const bool isEditable = NULL != mImpl->mEventData;
2198
2199   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2200   Vector2 offset;
2201   if( newSize && isEditable )
2202   {
2203     offset = mImpl->mModel->mScrollPosition;
2204   }
2205
2206   if( !isEditable || !IsMultiLineEnabled() )
2207   {
2208     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2209     CalculateVerticalOffset( size );
2210   }
2211
2212   if( isEditable )
2213   {
2214     if( newSize )
2215     {
2216       // If there is a new size, the scroll position needs to be clamped.
2217       mImpl->ClampHorizontalScroll( layoutSize );
2218
2219       // Update the decorator's positions is needed if there is a new size.
2220       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2221     }
2222
2223     // Move the cursor, grab handle etc.
2224     if( mImpl->ProcessInputEvents() )
2225     {
2226       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2227     }
2228   }
2229
2230   // Clear the update info. This info will be set the next time the text is updated.
2231   mImpl->mTextUpdateInfo.Clear();
2232   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2233
2234   return updateTextType;
2235 }
2236
2237 void Controller::RequestRelayout()
2238 {
2239   mImpl->RequestRelayout();
2240 }
2241
2242 // public : Input style change signals.
2243
2244 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2245 {
2246   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2247 }
2248
2249 void Controller::ProcessInputStyleChangedSignals()
2250 {
2251   if( NULL == mImpl->mEventData )
2252   {
2253     // Nothing to do.
2254     return;
2255   }
2256
2257   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2258          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2259        it != endIt;
2260        ++it )
2261   {
2262     const InputStyle::Mask mask = *it;
2263
2264     if( NULL != mImpl->mEditableControlInterface )
2265     {
2266       // Emit the input style changed signal.
2267       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2268     }
2269   }
2270
2271   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2272 }
2273
2274 // public : Text-input Event Queuing.
2275
2276 void Controller::KeyboardFocusGainEvent()
2277 {
2278   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2279
2280   if( NULL != mImpl->mEventData )
2281   {
2282     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2283         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2284     {
2285       mImpl->ChangeState( EventData::EDITING );
2286       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2287       mImpl->mEventData->mUpdateInputStyle = true;
2288     }
2289     mImpl->NotifyImfMultiLineStatus();
2290     if( mImpl->IsShowingPlaceholderText() )
2291     {
2292       // Show alternative placeholder-text when editing
2293       ShowPlaceholderText();
2294     }
2295
2296     mImpl->RequestRelayout();
2297   }
2298 }
2299
2300 void Controller::KeyboardFocusLostEvent()
2301 {
2302   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2303
2304   if( NULL != mImpl->mEventData )
2305   {
2306     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2307     {
2308       mImpl->ChangeState( EventData::INACTIVE );
2309
2310       if( !mImpl->IsShowingRealText() )
2311       {
2312         // Revert to regular placeholder-text when not editing
2313         ShowPlaceholderText();
2314       }
2315     }
2316   }
2317   mImpl->RequestRelayout();
2318 }
2319
2320 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2321 {
2322   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2323
2324   bool textChanged = false;
2325   bool relayoutNeeded = false;
2326
2327   if( ( NULL != mImpl->mEventData ) &&
2328       ( keyEvent.state == KeyEvent::Down ) )
2329   {
2330     int keyCode = keyEvent.keyCode;
2331     const std::string& keyString = keyEvent.keyPressed;
2332
2333     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2334
2335     // Pre-process to separate modifying events from non-modifying input events.
2336     if( isNullKey )
2337     {
2338       // In some platforms arrive key events with no key code.
2339       // Do nothing.
2340       return false;
2341     }
2342     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2343     {
2344       // Do nothing
2345       return false;
2346     }
2347     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2348              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2349              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2350              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2351     {
2352       // If don't have any text, do nothing.
2353       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2354       {
2355         return false;
2356       }
2357
2358       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2359       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2360       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2361       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2362
2363       // Logic to determine whether this text control will lose focus or not.
2364       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
2365           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
2366           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2367           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2368           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2369           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2370       {
2371         return false;
2372       }
2373
2374       mImpl->mEventData->mCheckScrollAmount = true;
2375       Event event( Event::CURSOR_KEY_EVENT );
2376       event.p1.mInt = keyCode;
2377       mImpl->mEventData->mEventQueue.push_back( event );
2378
2379       // Will request for relayout.
2380       relayoutNeeded = true;
2381     }
2382     else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
2383              ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
2384     {
2385       textChanged = DeleteEvent( keyCode );
2386
2387       // Will request for relayout.
2388       relayoutNeeded = true;
2389     }
2390     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2391              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2392              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2393     {
2394       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2395       mImpl->ChangeState( EventData::INACTIVE );
2396
2397       // Will request for relayout.
2398       relayoutNeeded = true;
2399
2400       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2401     }
2402     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2403     {
2404       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2405       // and a character is typed after the type of a upper case latin character.
2406
2407       // Do nothing.
2408       return false;
2409     }
2410     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2411     {
2412       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2413       // Do nothing.
2414       return false;
2415     }
2416     else
2417     {
2418       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2419
2420       // IMF manager is no longer handling key-events
2421       mImpl->ClearPreEditFlag();
2422
2423       InsertText( keyString, COMMIT );
2424       textChanged = true;
2425
2426       // Will request for relayout.
2427       relayoutNeeded = true;
2428     }
2429
2430     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2431          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2432          ( !isNullKey ) &&
2433          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2434          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2435          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2436     {
2437       // Should not change the state if the key is the shift send by the imf manager.
2438       // Otherwise, when the state is SELECTING the text controller can't send the right
2439       // surrounding info to the imf.
2440       mImpl->ChangeState( EventData::EDITING );
2441
2442       // Will request for relayout.
2443       relayoutNeeded = true;
2444     }
2445
2446     if( relayoutNeeded )
2447     {
2448       mImpl->RequestRelayout();
2449     }
2450   }
2451
2452   if( textChanged &&
2453       ( NULL != mImpl->mEditableControlInterface ) )
2454   {
2455     // Do this last since it provides callbacks into application code
2456     mImpl->mEditableControlInterface->TextChanged();
2457   }
2458
2459   return true;
2460 }
2461
2462 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2463 {
2464   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2465
2466   if( NULL != mImpl->mEventData )
2467   {
2468     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2469     EventData::State state( mImpl->mEventData->mState );
2470     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2471
2472     if( mImpl->IsClipboardVisible() )
2473     {
2474       if( EventData::INACTIVE == state || EventData::EDITING == state)
2475       {
2476         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2477       }
2478       relayoutNeeded = true;
2479     }
2480     else if( 1u == tapCount )
2481     {
2482       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2483       {
2484         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2485       }
2486
2487       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2488       {
2489         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2490         relayoutNeeded = true;
2491       }
2492       else
2493       {
2494         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2495         {
2496           // Hide placeholder text
2497           ResetText();
2498         }
2499
2500         if( EventData::INACTIVE == state )
2501         {
2502           mImpl->ChangeState( EventData::EDITING );
2503         }
2504         else if( !mImpl->IsClipboardEmpty() )
2505         {
2506           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2507         }
2508         relayoutNeeded = true;
2509       }
2510     }
2511     else if( 2u == tapCount )
2512     {
2513       if( mImpl->mEventData->mSelectionEnabled &&
2514           mImpl->IsShowingRealText() )
2515       {
2516         relayoutNeeded = true;
2517         mImpl->mEventData->mIsLeftHandleSelected = true;
2518         mImpl->mEventData->mIsRightHandleSelected = true;
2519       }
2520     }
2521
2522     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2523     if( relayoutNeeded )
2524     {
2525       Event event( Event::TAP_EVENT );
2526       event.p1.mUint = tapCount;
2527       event.p2.mFloat = x;
2528       event.p3.mFloat = y;
2529       mImpl->mEventData->mEventQueue.push_back( event );
2530
2531       mImpl->RequestRelayout();
2532     }
2533   }
2534
2535   // Reset keyboard as tap event has occurred.
2536   mImpl->ResetImfManager();
2537 }
2538
2539 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2540 {
2541   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2542
2543   if( NULL != mImpl->mEventData )
2544   {
2545     Event event( Event::PAN_EVENT );
2546     event.p1.mInt = state;
2547     event.p2.mFloat = displacement.x;
2548     event.p3.mFloat = displacement.y;
2549     mImpl->mEventData->mEventQueue.push_back( event );
2550
2551     mImpl->RequestRelayout();
2552   }
2553 }
2554
2555 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2556 {
2557   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2558
2559   if( ( state == Gesture::Started ) &&
2560       ( NULL != mImpl->mEventData ) )
2561   {
2562     // The 1st long-press on inactive text-field is treated as tap
2563     if( EventData::INACTIVE == mImpl->mEventData->mState )
2564     {
2565       mImpl->ChangeState( EventData::EDITING );
2566
2567       Event event( Event::TAP_EVENT );
2568       event.p1.mUint = 1;
2569       event.p2.mFloat = x;
2570       event.p3.mFloat = y;
2571       mImpl->mEventData->mEventQueue.push_back( event );
2572
2573       mImpl->RequestRelayout();
2574     }
2575     else if( !mImpl->IsShowingRealText() )
2576     {
2577       Event event( Event::LONG_PRESS_EVENT );
2578       event.p1.mInt = state;
2579       event.p2.mFloat = x;
2580       event.p3.mFloat = y;
2581       mImpl->mEventData->mEventQueue.push_back( event );
2582       mImpl->RequestRelayout();
2583     }
2584     else if( !mImpl->IsClipboardVisible() )
2585     {
2586       // Reset the imf manager to commit the pre-edit before selecting the text.
2587       mImpl->ResetImfManager();
2588
2589       Event event( Event::LONG_PRESS_EVENT );
2590       event.p1.mInt = state;
2591       event.p2.mFloat = x;
2592       event.p3.mFloat = y;
2593       mImpl->mEventData->mEventQueue.push_back( event );
2594       mImpl->RequestRelayout();
2595
2596       mImpl->mEventData->mIsLeftHandleSelected = true;
2597       mImpl->mEventData->mIsRightHandleSelected = true;
2598     }
2599   }
2600 }
2601
2602 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2603 {
2604   // Whether the text needs to be relaid-out.
2605   bool requestRelayout = false;
2606
2607   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2608   bool retrieveText = false;
2609   bool retrieveCursor = false;
2610
2611   switch( imfEvent.eventName )
2612   {
2613     case ImfManager::COMMIT:
2614     {
2615       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2616       requestRelayout = true;
2617       retrieveCursor = true;
2618       break;
2619     }
2620     case ImfManager::PREEDIT:
2621     {
2622       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2623       requestRelayout = true;
2624       retrieveCursor = true;
2625       break;
2626     }
2627     case ImfManager::DELETESURROUNDING:
2628     {
2629       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2630                                            imfEvent.numberOfChars,
2631                                            DONT_UPDATE_INPUT_STYLE );
2632
2633       if( textDeleted )
2634       {
2635         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2636             !mImpl->IsPlaceholderAvailable() )
2637         {
2638           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2639         }
2640         else
2641         {
2642           ShowPlaceholderText();
2643         }
2644         mImpl->mEventData->mUpdateCursorPosition = true;
2645         mImpl->mEventData->mScrollAfterDelete = true;
2646
2647         requestRelayout = true;
2648       }
2649       break;
2650     }
2651     case ImfManager::GETSURROUNDING:
2652     {
2653       retrieveText = true;
2654       retrieveCursor = true;
2655       break;
2656     }
2657     case ImfManager::PRIVATECOMMAND:
2658     {
2659       // PRIVATECOMMAND event is just for getting the private command message
2660       retrieveText = true;
2661       retrieveCursor = true;
2662       break;
2663     }
2664     case ImfManager::VOID:
2665     {
2666       // do nothing
2667       break;
2668     }
2669   } // end switch
2670
2671   if( requestRelayout )
2672   {
2673     mImpl->mOperationsPending = ALL_OPERATIONS;
2674     mImpl->RequestRelayout();
2675   }
2676
2677   std::string text;
2678   CharacterIndex cursorPosition = 0u;
2679   Length numberOfWhiteSpaces = 0u;
2680
2681   if( retrieveCursor )
2682   {
2683     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2684
2685     cursorPosition = mImpl->GetLogicalCursorPosition();
2686
2687     if( cursorPosition < numberOfWhiteSpaces )
2688     {
2689       cursorPosition = 0u;
2690     }
2691     else
2692     {
2693       cursorPosition -= numberOfWhiteSpaces;
2694     }
2695   }
2696
2697   if( retrieveText )
2698   {
2699     mImpl->GetText( numberOfWhiteSpaces, text );
2700   }
2701
2702   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2703
2704   if( requestRelayout &&
2705       ( NULL != mImpl->mEditableControlInterface ) )
2706   {
2707     // Do this last since it provides callbacks into application code
2708     mImpl->mEditableControlInterface->TextChanged();
2709   }
2710
2711   return callbackData;
2712 }
2713
2714 void Controller::PasteClipboardItemEvent()
2715 {
2716   // Retrieve the clipboard contents first
2717   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2718   std::string stringToPaste( notifier.GetContent() );
2719
2720   // Commit the current pre-edit text; the contents of the clipboard should be appended
2721   mImpl->ResetImfManager();
2722
2723   // Temporary disable hiding clipboard
2724   mImpl->SetClipboardHideEnable( false );
2725
2726   // Paste
2727   PasteText( stringToPaste );
2728
2729   mImpl->SetClipboardHideEnable( true );
2730 }
2731
2732 // protected : Inherit from Text::Decorator::ControllerInterface.
2733
2734 void Controller::GetTargetSize( Vector2& targetSize )
2735 {
2736   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2737 }
2738
2739 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2740 {
2741   if( NULL != mImpl->mEditableControlInterface )
2742   {
2743     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2744   }
2745 }
2746
2747 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2748 {
2749   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2750
2751   if( NULL != mImpl->mEventData )
2752   {
2753     switch( handleType )
2754     {
2755       case GRAB_HANDLE:
2756       {
2757         Event event( Event::GRAB_HANDLE_EVENT );
2758         event.p1.mUint  = state;
2759         event.p2.mFloat = x;
2760         event.p3.mFloat = y;
2761
2762         mImpl->mEventData->mEventQueue.push_back( event );
2763         break;
2764       }
2765       case LEFT_SELECTION_HANDLE:
2766       {
2767         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2768         event.p1.mUint  = state;
2769         event.p2.mFloat = x;
2770         event.p3.mFloat = y;
2771
2772         mImpl->mEventData->mEventQueue.push_back( event );
2773         break;
2774       }
2775       case RIGHT_SELECTION_HANDLE:
2776       {
2777         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2778         event.p1.mUint  = state;
2779         event.p2.mFloat = x;
2780         event.p3.mFloat = y;
2781
2782         mImpl->mEventData->mEventQueue.push_back( event );
2783         break;
2784       }
2785       case LEFT_SELECTION_HANDLE_MARKER:
2786       case RIGHT_SELECTION_HANDLE_MARKER:
2787       {
2788         // Markers do not move the handles.
2789         break;
2790       }
2791       case HANDLE_TYPE_COUNT:
2792       {
2793         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2794       }
2795     }
2796
2797     mImpl->RequestRelayout();
2798   }
2799 }
2800
2801 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2802
2803 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2804 {
2805   if( NULL == mImpl->mEventData )
2806   {
2807     return;
2808   }
2809
2810   switch( button )
2811   {
2812     case Toolkit::TextSelectionPopup::CUT:
2813     {
2814       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2815       mImpl->mOperationsPending = ALL_OPERATIONS;
2816
2817       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2818           !mImpl->IsPlaceholderAvailable() )
2819       {
2820         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2821       }
2822       else
2823       {
2824         ShowPlaceholderText();
2825       }
2826
2827       mImpl->mEventData->mUpdateCursorPosition = true;
2828       mImpl->mEventData->mScrollAfterDelete = true;
2829
2830       mImpl->RequestRelayout();
2831
2832       if( NULL != mImpl->mEditableControlInterface )
2833       {
2834         mImpl->mEditableControlInterface->TextChanged();
2835       }
2836       break;
2837     }
2838     case Toolkit::TextSelectionPopup::COPY:
2839     {
2840       mImpl->SendSelectionToClipboard( false ); // Text not modified
2841
2842       mImpl->mEventData->mUpdateCursorPosition = true;
2843
2844       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2845       break;
2846     }
2847     case Toolkit::TextSelectionPopup::PASTE:
2848     {
2849       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2850       break;
2851     }
2852     case Toolkit::TextSelectionPopup::SELECT:
2853     {
2854       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2855
2856       if( mImpl->mEventData->mSelectionEnabled )
2857       {
2858         // Creates a SELECT event.
2859         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2860       }
2861       break;
2862     }
2863     case Toolkit::TextSelectionPopup::SELECT_ALL:
2864     {
2865       // Creates a SELECT_ALL event
2866       SelectEvent( 0.f, 0.f, true );
2867       break;
2868     }
2869     case Toolkit::TextSelectionPopup::CLIPBOARD:
2870     {
2871       mImpl->ShowClipboard();
2872       break;
2873     }
2874     case Toolkit::TextSelectionPopup::NONE:
2875     {
2876       // Nothing to do.
2877       break;
2878     }
2879   }
2880 }
2881
2882 void Controller::DisplayTimeExpired()
2883 {
2884   mImpl->mEventData->mUpdateCursorPosition = true;
2885   // Apply modifications to the model
2886   mImpl->mOperationsPending = ALL_OPERATIONS;
2887
2888   mImpl->RequestRelayout();
2889 }
2890
2891 // private : Update.
2892
2893 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2894 {
2895   bool removedPrevious = false;
2896   bool removedSelected = false;
2897   bool maxLengthReached = false;
2898
2899   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2900
2901   if( NULL == mImpl->mEventData )
2902   {
2903     return;
2904   }
2905
2906   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2907                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2908                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2909
2910   // TODO: At the moment the underline runs are only for pre-edit.
2911   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2912
2913   // Remove the previous IMF pre-edit.
2914   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2915   {
2916     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2917                                   mImpl->mEventData->mPreEditLength,
2918                                   DONT_UPDATE_INPUT_STYLE );
2919
2920     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2921     mImpl->mEventData->mPreEditLength = 0u;
2922   }
2923   else
2924   {
2925     // Remove the previous Selection.
2926     removedSelected = RemoveSelectedText();
2927
2928   }
2929
2930   Vector<Character> utf32Characters;
2931   Length characterCount = 0u;
2932
2933   if( !text.empty() )
2934   {
2935     //  Convert text into UTF-32
2936     utf32Characters.Resize( text.size() );
2937
2938     // This is a bit horrible but std::string returns a (signed) char*
2939     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2940
2941     // Transform a text array encoded in utf8 into an array encoded in utf32.
2942     // It returns the actual number of characters.
2943     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2944     utf32Characters.Resize( characterCount );
2945
2946     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2947     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2948   }
2949
2950   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2951   {
2952     // The placeholder text is no longer needed
2953     if( mImpl->IsShowingPlaceholderText() )
2954     {
2955       ResetText();
2956     }
2957
2958     mImpl->ChangeState( EventData::EDITING );
2959
2960     // Handle the IMF (predicitive text) state changes
2961     if( COMMIT == type )
2962     {
2963       // IMF manager is no longer handling key-events
2964       mImpl->ClearPreEditFlag();
2965     }
2966     else // PRE_EDIT
2967     {
2968       if( !mImpl->mEventData->mPreEditFlag )
2969       {
2970         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2971
2972         // Record the start of the pre-edit text
2973         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2974       }
2975
2976       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2977       mImpl->mEventData->mPreEditFlag = true;
2978
2979       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2980     }
2981
2982     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2983
2984     // Restrict new text to fit within Maximum characters setting.
2985     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2986     maxLengthReached = ( characterCount > maxSizeOfNewText );
2987
2988     // The cursor position.
2989     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2990
2991     // Update the text's style.
2992
2993     // Updates the text style runs by adding characters.
2994     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2995
2996     // Get the character index from the cursor index.
2997     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2998
2999     // Retrieve the text's style for the given index.
3000     InputStyle style;
3001     mImpl->RetrieveDefaultInputStyle( style );
3002     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3003
3004     // Whether to add a new text color run.
3005     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
3006
3007     // Whether to add a new font run.
3008     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
3009     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
3010     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
3011     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
3012     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
3013
3014     // Add style runs.
3015     if( addColorRun )
3016     {
3017       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3018       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3019
3020       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3021       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3022       colorRun.characterRun.characterIndex = cursorIndex;
3023       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3024     }
3025
3026     if( addFontNameRun   ||
3027         addFontWeightRun ||
3028         addFontWidthRun  ||
3029         addFontSlantRun  ||
3030         addFontSizeRun )
3031     {
3032       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3033       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3034
3035       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3036
3037       if( addFontNameRun )
3038       {
3039         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3040         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3041         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3042         fontDescriptionRun.familyDefined = true;
3043
3044         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3045       }
3046
3047       if( addFontWeightRun )
3048       {
3049         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3050         fontDescriptionRun.weightDefined = true;
3051       }
3052
3053       if( addFontWidthRun )
3054       {
3055         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3056         fontDescriptionRun.widthDefined = true;
3057       }
3058
3059       if( addFontSlantRun )
3060       {
3061         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3062         fontDescriptionRun.slantDefined = true;
3063       }
3064
3065       if( addFontSizeRun )
3066       {
3067         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3068         fontDescriptionRun.sizeDefined = true;
3069       }
3070
3071       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3072       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3073     }
3074
3075     // Insert at current cursor position.
3076     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3077
3078     if( cursorIndex < numberOfCharactersInModel )
3079     {
3080       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3081     }
3082     else
3083     {
3084       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3085     }
3086
3087     // Mark the first paragraph to be updated.
3088     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3089     {
3090       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3091       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3092       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3093       mImpl->mTextUpdateInfo.mClearAll = true;
3094     }
3095     else
3096     {
3097       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3098       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3099     }
3100
3101     // Update the cursor index.
3102     cursorIndex += maxSizeOfNewText;
3103
3104     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
3105   }
3106
3107   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3108       mImpl->IsPlaceholderAvailable() )
3109   {
3110     // Show place-holder if empty after removing the pre-edit text
3111     ShowPlaceholderText();
3112     mImpl->mEventData->mUpdateCursorPosition = true;
3113     mImpl->ClearPreEditFlag();
3114   }
3115   else if( removedPrevious ||
3116            removedSelected ||
3117            ( 0 != utf32Characters.Count() ) )
3118   {
3119     // Queue an inserted event
3120     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3121
3122     mImpl->mEventData->mUpdateCursorPosition = true;
3123     if( removedSelected )
3124     {
3125       mImpl->mEventData->mScrollAfterDelete = true;
3126     }
3127     else
3128     {
3129       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3130     }
3131   }
3132
3133   if( maxLengthReached )
3134   {
3135     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3136
3137     mImpl->ResetImfManager();
3138
3139     if( NULL != mImpl->mEditableControlInterface )
3140     {
3141       // Do this last since it provides callbacks into application code
3142       mImpl->mEditableControlInterface->MaxLengthReached();
3143     }
3144   }
3145 }
3146
3147 void Controller::PasteText( const std::string& stringToPaste )
3148 {
3149   InsertText( stringToPaste, Text::Controller::COMMIT );
3150   mImpl->ChangeState( EventData::EDITING );
3151   mImpl->RequestRelayout();
3152
3153   if( NULL != mImpl->mEditableControlInterface )
3154   {
3155     // Do this last since it provides callbacks into application code
3156     mImpl->mEditableControlInterface->TextChanged();
3157   }
3158 }
3159
3160 bool Controller::RemoveText( int cursorOffset,
3161                              int numberOfCharacters,
3162                              UpdateInputStyleType type )
3163 {
3164   bool removed = false;
3165
3166   if( NULL == mImpl->mEventData )
3167   {
3168     return removed;
3169   }
3170
3171   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3172                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3173
3174   if( !mImpl->IsShowingPlaceholderText() )
3175   {
3176     // Delete at current cursor position
3177     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3178     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3179
3180     CharacterIndex cursorIndex = 0;
3181
3182     // Validate the cursor position & number of characters
3183     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3184     {
3185       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3186     }
3187
3188     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3189     {
3190       numberOfCharacters = currentText.Count() - cursorIndex;
3191     }
3192
3193     if( mImpl->mEventData->mPreEditFlag || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time.
3194         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
3195     {
3196       // Mark the paragraphs to be updated.
3197       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3198       {
3199         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3200         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3201         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3202         mImpl->mTextUpdateInfo.mClearAll = true;
3203       }
3204       else
3205       {
3206         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3207         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3208       }
3209
3210       // Update the input style and remove the text's style before removing the text.
3211
3212       if( UPDATE_INPUT_STYLE == type )
3213       {
3214         // Keep a copy of the current input style.
3215         InputStyle currentInputStyle;
3216         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3217
3218         // Set first the default input style.
3219         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3220
3221         // Update the input style.
3222         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3223
3224         // Compare if the input style has changed.
3225         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3226
3227         if( hasInputStyleChanged )
3228         {
3229           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3230           // Queue the input style changed signal.
3231           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3232         }
3233       }
3234
3235       // Updates the text style runs by removing characters. Runs with no characters are removed.
3236       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3237
3238       // Remove the characters.
3239       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3240       Vector<Character>::Iterator last  = first + numberOfCharacters;
3241
3242       currentText.Erase( first, last );
3243
3244       // Cursor position retreat
3245       oldCursorIndex = cursorIndex;
3246
3247       mImpl->mEventData->mScrollAfterDelete = true;
3248
3249       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3250       removed = true;
3251     }
3252   }
3253
3254   return removed;
3255 }
3256
3257 bool Controller::RemoveSelectedText()
3258 {
3259   bool textRemoved( false );
3260
3261   if( EventData::SELECTING == mImpl->mEventData->mState )
3262   {
3263     std::string removedString;
3264     mImpl->RetrieveSelection( removedString, true );
3265
3266     if( !removedString.empty() )
3267     {
3268       textRemoved = true;
3269       mImpl->ChangeState( EventData::EDITING );
3270     }
3271   }
3272
3273   return textRemoved;
3274 }
3275
3276 // private : Relayout.
3277
3278 bool Controller::DoRelayout( const Size& size,
3279                              OperationsMask operationsRequired,
3280                              Size& layoutSize )
3281 {
3282   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3283   bool viewUpdated( false );
3284
3285   // Calculate the operations to be done.
3286   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3287
3288   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3289   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3290
3291   // Get the current layout size.
3292   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3293
3294   if( NO_OPERATION != ( LAYOUT & operations ) )
3295   {
3296     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3297
3298     // Some vectors with data needed to layout and reorder may be void
3299     // after the first time the text has been laid out.
3300     // Fill the vectors again.
3301
3302     // Calculate the number of glyphs to layout.
3303     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3304     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3305     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3306     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3307
3308     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3309     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3310     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3311     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3312
3313     if( 0u == totalNumberOfGlyphs )
3314     {
3315       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3316       {
3317         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3318       }
3319
3320       // Nothing else to do if there is no glyphs.
3321       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3322       return true;
3323     }
3324
3325     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3326     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3327     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3328     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3329     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3330     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3331     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3332     float outlineWidth = mImpl->mModel->GetOutlineWidth();
3333
3334     // Set the layout parameters.
3335     Layout::Parameters layoutParameters( size,
3336                                          textBuffer,
3337                                          lineBreakInfo.Begin(),
3338                                          wordBreakInfo.Begin(),
3339                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3340                                          glyphs.Begin(),
3341                                          glyphsToCharactersMap.Begin(),
3342                                          charactersPerGlyph.Begin(),
3343                                          charactersToGlyphBuffer,
3344                                          glyphsPerCharacterBuffer,
3345                                          totalNumberOfGlyphs,
3346                                          mImpl->mModel->mHorizontalAlignment,
3347                                          mImpl->mModel->mLineWrapMode,
3348                                          outlineWidth );
3349
3350     // Resize the vector of positions to have the same size than the vector of glyphs.
3351     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3352     glyphPositions.Resize( totalNumberOfGlyphs );
3353
3354     // Whether the last character is a new paragraph character.
3355     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3356     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3357
3358     // The initial glyph and the number of glyphs to layout.
3359     layoutParameters.startGlyphIndex = startGlyphIndex;
3360     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3361     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3362     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3363
3364     // Update the ellipsis
3365     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3366
3367     if( NULL != mImpl->mEventData )
3368     {
3369       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3370       {
3371         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3372       }
3373       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3374       {
3375         // Disable ellipsis when editing
3376         elideTextEnabled = false;
3377       }
3378
3379       // Reset the scroll position in inactive state
3380       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3381       {
3382         ResetScrollPosition();
3383       }
3384     }
3385
3386     // Update the visual model.
3387     Size newLayoutSize;
3388     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3389                                                    glyphPositions,
3390                                                    mImpl->mModel->mVisualModel->mLines,
3391                                                    newLayoutSize,
3392                                                    elideTextEnabled );
3393
3394     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3395
3396     if( viewUpdated )
3397     {
3398       layoutSize = newLayoutSize;
3399
3400       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3401       {
3402         mImpl->mAutoScrollDirectionRTL = false;
3403       }
3404
3405       // Reorder the lines
3406       if( NO_OPERATION != ( REORDER & operations ) )
3407       {
3408         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3409         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3410
3411         // Check first if there are paragraphs with bidirectional info.
3412         if( 0u != bidirectionalInfo.Count() )
3413         {
3414           // Get the lines
3415           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3416
3417           // Reorder the lines.
3418           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3419           ReorderLines( bidirectionalInfo,
3420                         startIndex,
3421                         requestedNumberOfCharacters,
3422                         mImpl->mModel->mVisualModel->mLines,
3423                         bidirectionalLineInfo );
3424
3425           // Set the bidirectional info per line into the layout parameters.
3426           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3427           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3428
3429           // Re-layout the text. Reorder those lines with right to left characters.
3430           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3431                                                          startIndex,
3432                                                          requestedNumberOfCharacters,
3433                                                          glyphPositions );
3434
3435           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3436           {
3437             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3438             if ( firstline )
3439             {
3440               mImpl->mAutoScrollDirectionRTL = firstline->direction;
3441             }
3442           }
3443         }
3444       } // REORDER
3445
3446       // Sets the layout size.
3447       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3448       {
3449         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3450       }
3451     } // view updated
3452   }
3453
3454   if( NO_OPERATION != ( ALIGN & operations ) )
3455   {
3456     // The laid-out lines.
3457     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3458
3459     // Need to align with the control's size as the text may contain lines
3460     // starting either with left to right text or right to left.
3461     mImpl->mLayoutEngine.Align( size,
3462                                 startIndex,
3463                                 requestedNumberOfCharacters,
3464                                 mImpl->mModel->mHorizontalAlignment,
3465                                 lines,
3466                                 mImpl->mModel->mAlignmentOffset );
3467
3468     viewUpdated = true;
3469   }
3470 #if defined(DEBUG_ENABLED)
3471   std::string currentText;
3472   GetText( currentText );
3473   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
3474 #endif
3475   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3476   return viewUpdated;
3477 }
3478
3479 void Controller::CalculateVerticalOffset( const Size& controlSize )
3480 {
3481   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3482
3483   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3484   {
3485     // Get the line height of the default font.
3486     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3487   }
3488
3489   switch( mImpl->mModel->mVerticalAlignment )
3490   {
3491     case VerticalAlignment::TOP:
3492     {
3493       mImpl->mModel->mScrollPosition.y = 0.f;
3494       break;
3495     }
3496     case VerticalAlignment::CENTER:
3497     {
3498       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3499       break;
3500     }
3501     case VerticalAlignment::BOTTOM:
3502     {
3503       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3504       break;
3505     }
3506   }
3507 }
3508
3509 // private : Events.
3510
3511 void Controller::ProcessModifyEvents()
3512 {
3513   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3514
3515   if( 0u == events.Count() )
3516   {
3517     // Nothing to do.
3518     return;
3519   }
3520
3521   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3522          endIt = events.End();
3523        it != endIt;
3524        ++it )
3525   {
3526     const ModifyEvent& event = *it;
3527
3528     if( ModifyEvent::TEXT_REPLACED == event.type )
3529     {
3530       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3531       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3532
3533       TextReplacedEvent();
3534     }
3535     else if( ModifyEvent::TEXT_INSERTED == event.type )
3536     {
3537       TextInsertedEvent();
3538     }
3539     else if( ModifyEvent::TEXT_DELETED == event.type )
3540     {
3541       // Placeholder-text cannot be deleted
3542       if( !mImpl->IsShowingPlaceholderText() )
3543       {
3544         TextDeletedEvent();
3545       }
3546     }
3547   }
3548
3549   if( NULL != mImpl->mEventData )
3550   {
3551     // When the text is being modified, delay cursor blinking
3552     mImpl->mEventData->mDecorator->DelayCursorBlink();
3553   }
3554
3555   // Discard temporary text
3556   events.Clear();
3557 }
3558
3559 void Controller::TextReplacedEvent()
3560 {
3561   // The natural size needs to be re-calculated.
3562   mImpl->mRecalculateNaturalSize = true;
3563
3564   // Apply modifications to the model
3565   mImpl->mOperationsPending = ALL_OPERATIONS;
3566 }
3567
3568 void Controller::TextInsertedEvent()
3569 {
3570   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3571
3572   if( NULL == mImpl->mEventData )
3573   {
3574     return;
3575   }
3576
3577   mImpl->mEventData->mCheckScrollAmount = true;
3578
3579   // The natural size needs to be re-calculated.
3580   mImpl->mRecalculateNaturalSize = true;
3581
3582   // Apply modifications to the model; TODO - Optimize this
3583   mImpl->mOperationsPending = ALL_OPERATIONS;
3584 }
3585
3586 void Controller::TextDeletedEvent()
3587 {
3588   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3589
3590   if( NULL == mImpl->mEventData )
3591   {
3592     return;
3593   }
3594
3595   mImpl->mEventData->mCheckScrollAmount = true;
3596
3597   // The natural size needs to be re-calculated.
3598   mImpl->mRecalculateNaturalSize = true;
3599
3600   // Apply modifications to the model; TODO - Optimize this
3601   mImpl->mOperationsPending = ALL_OPERATIONS;
3602 }
3603
3604 void Controller::SelectEvent( float x, float y, bool selectAll )
3605 {
3606   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3607
3608   if( NULL != mImpl->mEventData )
3609   {
3610     if( selectAll )
3611     {
3612       Event event( Event::SELECT_ALL );
3613       mImpl->mEventData->mEventQueue.push_back( event );
3614     }
3615     else
3616     {
3617       Event event( Event::SELECT );
3618       event.p2.mFloat = x;
3619       event.p3.mFloat = y;
3620       mImpl->mEventData->mEventQueue.push_back( event );
3621     }
3622
3623     mImpl->mEventData->mCheckScrollAmount = true;
3624     mImpl->mEventData->mIsLeftHandleSelected = true;
3625     mImpl->mEventData->mIsRightHandleSelected = true;
3626     mImpl->RequestRelayout();
3627   }
3628 }
3629
3630 bool Controller::DeleteEvent( int keyCode )
3631 {
3632   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
3633
3634   bool removed = false;
3635
3636   if( NULL == mImpl->mEventData )
3637   {
3638     return removed;
3639   }
3640
3641   // IMF manager is no longer handling key-events
3642   mImpl->ClearPreEditFlag();
3643
3644   if( EventData::SELECTING == mImpl->mEventData->mState )
3645   {
3646     removed = RemoveSelectedText();
3647   }
3648   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
3649   {
3650     // Remove the character before the current cursor position
3651     removed = RemoveText( -1,
3652                           1,
3653                           UPDATE_INPUT_STYLE );
3654   }
3655   else if( ( mImpl->mEventData->mPrimaryCursorPosition >= 0 ) && ( keyCode == Dali::DevelKey::DALI_KEY_DELETE ) )
3656   {
3657     // Remove the character after the current cursor position
3658     removed = RemoveText( 0,
3659                           1,
3660                           UPDATE_INPUT_STYLE );
3661   }
3662
3663   if( removed )
3664   {
3665     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3666         !mImpl->IsPlaceholderAvailable() )
3667     {
3668       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3669     }
3670     else
3671     {
3672       ShowPlaceholderText();
3673     }
3674     mImpl->mEventData->mUpdateCursorPosition = true;
3675     mImpl->mEventData->mScrollAfterDelete = true;
3676   }
3677
3678   return removed;
3679 }
3680
3681 // private : Helpers.
3682
3683 void Controller::ResetText()
3684 {
3685   // Reset buffers.
3686   mImpl->mModel->mLogicalModel->mText.Clear();
3687
3688   // We have cleared everything including the placeholder-text
3689   mImpl->PlaceholderCleared();
3690
3691   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3692   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3693   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3694
3695   // Clear any previous text.
3696   mImpl->mTextUpdateInfo.mClearAll = true;
3697
3698   // The natural size needs to be re-calculated.
3699   mImpl->mRecalculateNaturalSize = true;
3700
3701   // Apply modifications to the model
3702   mImpl->mOperationsPending = ALL_OPERATIONS;
3703 }
3704
3705 void Controller::ShowPlaceholderText()
3706 {
3707   if( mImpl->IsPlaceholderAvailable() )
3708   {
3709     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3710
3711     if( NULL == mImpl->mEventData )
3712     {
3713       return;
3714     }
3715
3716     mImpl->mEventData->mIsShowingPlaceholderText = true;
3717
3718     // Disable handles when showing place-holder text
3719     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3720     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3721     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3722
3723     const char* text( NULL );
3724     size_t size( 0 );
3725
3726     // TODO - Switch Placeholder text when changing state
3727     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3728         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3729     {
3730       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3731       size = mImpl->mEventData->mPlaceholderTextActive.size();
3732     }
3733     else
3734     {
3735       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3736       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3737     }
3738
3739     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3740     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3741
3742     // Reset model for showing placeholder.
3743     mImpl->mModel->mLogicalModel->mText.Clear();
3744     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3745
3746     // Convert text into UTF-32
3747     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3748     utf32Characters.Resize( size );
3749
3750     // This is a bit horrible but std::string returns a (signed) char*
3751     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3752
3753     // Transform a text array encoded in utf8 into an array encoded in utf32.
3754     // It returns the actual number of characters.
3755     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3756     utf32Characters.Resize( characterCount );
3757
3758     // The characters to be added.
3759     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3760
3761     // Reset the cursor position
3762     mImpl->mEventData->mPrimaryCursorPosition = 0;
3763
3764     // The natural size needs to be re-calculated.
3765     mImpl->mRecalculateNaturalSize = true;
3766
3767     // Apply modifications to the model
3768     mImpl->mOperationsPending = ALL_OPERATIONS;
3769
3770     // Update the rest of the model during size negotiation
3771     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3772   }
3773 }
3774
3775 void Controller::ClearFontData()
3776 {
3777   if( mImpl->mFontDefaults )
3778   {
3779     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3780   }
3781
3782   // Set flags to update the model.
3783   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3784   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3785   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3786
3787   mImpl->mTextUpdateInfo.mClearAll = true;
3788   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3789   mImpl->mRecalculateNaturalSize = true;
3790
3791   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3792                                                            VALIDATE_FONTS            |
3793                                                            SHAPE_TEXT                |
3794                                                            GET_GLYPH_METRICS         |
3795                                                            LAYOUT                    |
3796                                                            UPDATE_LAYOUT_SIZE        |
3797                                                            REORDER                   |
3798                                                            ALIGN );
3799 }
3800
3801 void Controller::ClearStyleData()
3802 {
3803   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3804   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3805 }
3806
3807 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3808 {
3809   // Reset the cursor position
3810   if( NULL != mImpl->mEventData )
3811   {
3812     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3813
3814     // Update the cursor if it's in editing mode.
3815     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3816     {
3817       mImpl->mEventData->mUpdateCursorPosition = true;
3818     }
3819   }
3820 }
3821
3822 void Controller::ResetScrollPosition()
3823 {
3824   if( NULL != mImpl->mEventData )
3825   {
3826     // Reset the scroll position.
3827     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3828     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3829   }
3830 }
3831
3832 void Controller::SetControlInterface( ControlInterface* controlInterface )
3833 {
3834   mImpl->mControlInterface = controlInterface;
3835 }
3836
3837 bool Controller::ShouldClearFocusOnEscape() const
3838 {
3839   return mImpl->mShouldClearFocusOnEscape;
3840 }
3841
3842 // private : Private contructors & copy operator.
3843
3844 Controller::Controller()
3845 : mImpl( NULL )
3846 {
3847   mImpl = new Controller::Impl( NULL, NULL );
3848 }
3849
3850 Controller::Controller( ControlInterface* controlInterface )
3851 {
3852   mImpl = new Controller::Impl( controlInterface, NULL );
3853 }
3854
3855 Controller::Controller( ControlInterface* controlInterface,
3856                         EditableControlInterface* editableControlInterface )
3857 {
3858   mImpl = new Controller::Impl( controlInterface,
3859                                 editableControlInterface );
3860 }
3861
3862 // The copy constructor and operator are left unimplemented.
3863
3864 // protected : Destructor.
3865
3866 Controller::~Controller()
3867 {
3868   delete mImpl;
3869 }
3870
3871 } // namespace Text
3872
3873 } // namespace Toolkit
3874
3875 } // namespace Dali