[4.0] Added text direction property
[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 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
2110 {
2111   const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
2112   if ( firstline && firstline->direction )
2113   {
2114     return Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT;
2115   }
2116
2117   return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
2118 }
2119
2120 // public : Relayout.
2121
2122 Controller::UpdateTextType Controller::Relayout( const Size& size )
2123 {
2124   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2125
2126   UpdateTextType updateTextType = NONE_UPDATED;
2127
2128   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2129   {
2130     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2131     {
2132       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2133       updateTextType = MODEL_UPDATED;
2134     }
2135
2136     // Clear the update info. This info will be set the next time the text is updated.
2137     mImpl->mTextUpdateInfo.Clear();
2138
2139     // Not worth to relayout if width or height is equal to zero.
2140     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2141
2142     return updateTextType;
2143   }
2144
2145   // Whether a new size has been set.
2146   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2147
2148   if( newSize )
2149   {
2150     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2151
2152     // Layout operations that need to be done if the size changes.
2153     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2154                                                              LAYOUT                    |
2155                                                              ALIGN                     |
2156                                                              UPDATE_LAYOUT_SIZE        |
2157                                                              REORDER );
2158     // Set the update info to relayout the whole text.
2159     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2160     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2161
2162     // Store the size used to layout the text.
2163     mImpl->mModel->mVisualModel->mControlSize = size;
2164   }
2165
2166   // Whether there are modify events.
2167   if( 0u != mImpl->mModifyEvents.Count() )
2168   {
2169     // Style operations that need to be done if the text is modified.
2170     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2171                                                              COLOR );
2172   }
2173
2174   // Set the update info to elide the text.
2175   if( mImpl->mModel->mElideEnabled ||
2176       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2177   {
2178     // Update Text layout for applying elided
2179     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2180                                                              ALIGN                     |
2181                                                              LAYOUT                    |
2182                                                              UPDATE_LAYOUT_SIZE        |
2183                                                              REORDER );
2184     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2185     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2186   }
2187
2188   // Make sure the model is up-to-date before layouting.
2189   ProcessModifyEvents();
2190   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2191
2192   // Layout the text.
2193   Size layoutSize;
2194   updated = DoRelayout( size,
2195                         mImpl->mOperationsPending,
2196                         layoutSize ) || updated;
2197
2198   if( updated )
2199   {
2200     updateTextType = MODEL_UPDATED;
2201   }
2202
2203   // Do not re-do any operation until something changes.
2204   mImpl->mOperationsPending = NO_OPERATION;
2205   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2206
2207   // Whether the text control is editable
2208   const bool isEditable = NULL != mImpl->mEventData;
2209
2210   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2211   Vector2 offset;
2212   if( newSize && isEditable )
2213   {
2214     offset = mImpl->mModel->mScrollPosition;
2215   }
2216
2217   if( !isEditable || !IsMultiLineEnabled() )
2218   {
2219     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2220     CalculateVerticalOffset( size );
2221   }
2222
2223   if( isEditable )
2224   {
2225     if( newSize )
2226     {
2227       // If there is a new size, the scroll position needs to be clamped.
2228       mImpl->ClampHorizontalScroll( layoutSize );
2229
2230       // Update the decorator's positions is needed if there is a new size.
2231       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2232     }
2233
2234     // Move the cursor, grab handle etc.
2235     if( mImpl->ProcessInputEvents() )
2236     {
2237       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2238     }
2239   }
2240
2241   // Clear the update info. This info will be set the next time the text is updated.
2242   mImpl->mTextUpdateInfo.Clear();
2243   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2244
2245   return updateTextType;
2246 }
2247
2248 void Controller::RequestRelayout()
2249 {
2250   mImpl->RequestRelayout();
2251 }
2252
2253 // public : Input style change signals.
2254
2255 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2256 {
2257   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2258 }
2259
2260 void Controller::ProcessInputStyleChangedSignals()
2261 {
2262   if( NULL == mImpl->mEventData )
2263   {
2264     // Nothing to do.
2265     return;
2266   }
2267
2268   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2269          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2270        it != endIt;
2271        ++it )
2272   {
2273     const InputStyle::Mask mask = *it;
2274
2275     if( NULL != mImpl->mEditableControlInterface )
2276     {
2277       // Emit the input style changed signal.
2278       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2279     }
2280   }
2281
2282   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2283 }
2284
2285 // public : Text-input Event Queuing.
2286
2287 void Controller::KeyboardFocusGainEvent()
2288 {
2289   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2290
2291   if( NULL != mImpl->mEventData )
2292   {
2293     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2294         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2295     {
2296       mImpl->ChangeState( EventData::EDITING );
2297       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2298       mImpl->mEventData->mUpdateInputStyle = true;
2299     }
2300     mImpl->NotifyImfMultiLineStatus();
2301     if( mImpl->IsShowingPlaceholderText() )
2302     {
2303       // Show alternative placeholder-text when editing
2304       ShowPlaceholderText();
2305     }
2306
2307     mImpl->RequestRelayout();
2308   }
2309 }
2310
2311 void Controller::KeyboardFocusLostEvent()
2312 {
2313   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2314
2315   if( NULL != mImpl->mEventData )
2316   {
2317     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2318     {
2319       mImpl->ChangeState( EventData::INACTIVE );
2320
2321       if( !mImpl->IsShowingRealText() )
2322       {
2323         // Revert to regular placeholder-text when not editing
2324         ShowPlaceholderText();
2325       }
2326     }
2327   }
2328   mImpl->RequestRelayout();
2329 }
2330
2331 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2332 {
2333   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2334
2335   bool textChanged = false;
2336   bool relayoutNeeded = false;
2337
2338   if( ( NULL != mImpl->mEventData ) &&
2339       ( keyEvent.state == KeyEvent::Down ) )
2340   {
2341     int keyCode = keyEvent.keyCode;
2342     const std::string& keyString = keyEvent.keyPressed;
2343
2344     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2345
2346     // Pre-process to separate modifying events from non-modifying input events.
2347     if( isNullKey )
2348     {
2349       // In some platforms arrive key events with no key code.
2350       // Do nothing.
2351       return false;
2352     }
2353     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2354     {
2355       // Do nothing
2356       return false;
2357     }
2358     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2359              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2360              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2361              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2362     {
2363       // If don't have any text, do nothing.
2364       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2365       {
2366         return false;
2367       }
2368
2369       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2370       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2371       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2372       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2373
2374       // Logic to determine whether this text control will lose focus or not.
2375       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
2376           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
2377           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2378           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2379           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2380           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2381       {
2382         return false;
2383       }
2384
2385       mImpl->mEventData->mCheckScrollAmount = true;
2386       Event event( Event::CURSOR_KEY_EVENT );
2387       event.p1.mInt = keyCode;
2388       mImpl->mEventData->mEventQueue.push_back( event );
2389
2390       // Will request for relayout.
2391       relayoutNeeded = true;
2392     }
2393     else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
2394              ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
2395     {
2396       textChanged = DeleteEvent( keyCode );
2397
2398       // Will request for relayout.
2399       relayoutNeeded = true;
2400     }
2401     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2402              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2403              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2404     {
2405       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2406       mImpl->ChangeState( EventData::INACTIVE );
2407
2408       // Will request for relayout.
2409       relayoutNeeded = true;
2410
2411       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2412     }
2413     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2414     {
2415       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2416       // and a character is typed after the type of a upper case latin character.
2417
2418       // Do nothing.
2419       return false;
2420     }
2421     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2422     {
2423       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2424       // Do nothing.
2425       return false;
2426     }
2427     else
2428     {
2429       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2430
2431       // IMF manager is no longer handling key-events
2432       mImpl->ClearPreEditFlag();
2433
2434       InsertText( keyString, COMMIT );
2435       textChanged = true;
2436
2437       // Will request for relayout.
2438       relayoutNeeded = true;
2439     }
2440
2441     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2442          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2443          ( !isNullKey ) &&
2444          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2445          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2446          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2447     {
2448       // Should not change the state if the key is the shift send by the imf manager.
2449       // Otherwise, when the state is SELECTING the text controller can't send the right
2450       // surrounding info to the imf.
2451       mImpl->ChangeState( EventData::EDITING );
2452
2453       // Will request for relayout.
2454       relayoutNeeded = true;
2455     }
2456
2457     if( relayoutNeeded )
2458     {
2459       mImpl->RequestRelayout();
2460     }
2461   }
2462
2463   if( textChanged &&
2464       ( NULL != mImpl->mEditableControlInterface ) )
2465   {
2466     // Do this last since it provides callbacks into application code
2467     mImpl->mEditableControlInterface->TextChanged();
2468   }
2469
2470   return true;
2471 }
2472
2473 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2474 {
2475   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2476
2477   if( NULL != mImpl->mEventData )
2478   {
2479     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2480     EventData::State state( mImpl->mEventData->mState );
2481     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2482
2483     if( mImpl->IsClipboardVisible() )
2484     {
2485       if( EventData::INACTIVE == state || EventData::EDITING == state)
2486       {
2487         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2488       }
2489       relayoutNeeded = true;
2490     }
2491     else if( 1u == tapCount )
2492     {
2493       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2494       {
2495         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2496       }
2497
2498       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2499       {
2500         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2501         relayoutNeeded = true;
2502       }
2503       else
2504       {
2505         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2506         {
2507           // Hide placeholder text
2508           ResetText();
2509         }
2510
2511         if( EventData::INACTIVE == state )
2512         {
2513           mImpl->ChangeState( EventData::EDITING );
2514         }
2515         else if( !mImpl->IsClipboardEmpty() )
2516         {
2517           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2518         }
2519         relayoutNeeded = true;
2520       }
2521     }
2522     else if( 2u == tapCount )
2523     {
2524       if( mImpl->mEventData->mSelectionEnabled &&
2525           mImpl->IsShowingRealText() )
2526       {
2527         relayoutNeeded = true;
2528         mImpl->mEventData->mIsLeftHandleSelected = true;
2529         mImpl->mEventData->mIsRightHandleSelected = true;
2530       }
2531     }
2532
2533     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2534     if( relayoutNeeded )
2535     {
2536       Event event( Event::TAP_EVENT );
2537       event.p1.mUint = tapCount;
2538       event.p2.mFloat = x;
2539       event.p3.mFloat = y;
2540       mImpl->mEventData->mEventQueue.push_back( event );
2541
2542       mImpl->RequestRelayout();
2543     }
2544   }
2545
2546   // Reset keyboard as tap event has occurred.
2547   mImpl->ResetImfManager();
2548 }
2549
2550 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2551 {
2552   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2553
2554   if( NULL != mImpl->mEventData )
2555   {
2556     Event event( Event::PAN_EVENT );
2557     event.p1.mInt = state;
2558     event.p2.mFloat = displacement.x;
2559     event.p3.mFloat = displacement.y;
2560     mImpl->mEventData->mEventQueue.push_back( event );
2561
2562     mImpl->RequestRelayout();
2563   }
2564 }
2565
2566 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2567 {
2568   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2569
2570   if( ( state == Gesture::Started ) &&
2571       ( NULL != mImpl->mEventData ) )
2572   {
2573     // The 1st long-press on inactive text-field is treated as tap
2574     if( EventData::INACTIVE == mImpl->mEventData->mState )
2575     {
2576       mImpl->ChangeState( EventData::EDITING );
2577
2578       Event event( Event::TAP_EVENT );
2579       event.p1.mUint = 1;
2580       event.p2.mFloat = x;
2581       event.p3.mFloat = y;
2582       mImpl->mEventData->mEventQueue.push_back( event );
2583
2584       mImpl->RequestRelayout();
2585     }
2586     else if( !mImpl->IsShowingRealText() )
2587     {
2588       Event event( Event::LONG_PRESS_EVENT );
2589       event.p1.mInt = state;
2590       event.p2.mFloat = x;
2591       event.p3.mFloat = y;
2592       mImpl->mEventData->mEventQueue.push_back( event );
2593       mImpl->RequestRelayout();
2594     }
2595     else if( !mImpl->IsClipboardVisible() )
2596     {
2597       // Reset the imf manager to commit the pre-edit before selecting the text.
2598       mImpl->ResetImfManager();
2599
2600       Event event( Event::LONG_PRESS_EVENT );
2601       event.p1.mInt = state;
2602       event.p2.mFloat = x;
2603       event.p3.mFloat = y;
2604       mImpl->mEventData->mEventQueue.push_back( event );
2605       mImpl->RequestRelayout();
2606
2607       mImpl->mEventData->mIsLeftHandleSelected = true;
2608       mImpl->mEventData->mIsRightHandleSelected = true;
2609     }
2610   }
2611 }
2612
2613 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2614 {
2615   // Whether the text needs to be relaid-out.
2616   bool requestRelayout = false;
2617
2618   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2619   bool retrieveText = false;
2620   bool retrieveCursor = false;
2621
2622   switch( imfEvent.eventName )
2623   {
2624     case ImfManager::COMMIT:
2625     {
2626       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2627       requestRelayout = true;
2628       retrieveCursor = true;
2629       break;
2630     }
2631     case ImfManager::PREEDIT:
2632     {
2633       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2634       requestRelayout = true;
2635       retrieveCursor = true;
2636       break;
2637     }
2638     case ImfManager::DELETESURROUNDING:
2639     {
2640       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2641                                            imfEvent.numberOfChars,
2642                                            DONT_UPDATE_INPUT_STYLE );
2643
2644       if( textDeleted )
2645       {
2646         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2647             !mImpl->IsPlaceholderAvailable() )
2648         {
2649           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2650         }
2651         else
2652         {
2653           ShowPlaceholderText();
2654         }
2655         mImpl->mEventData->mUpdateCursorPosition = true;
2656         mImpl->mEventData->mScrollAfterDelete = true;
2657
2658         requestRelayout = true;
2659       }
2660       break;
2661     }
2662     case ImfManager::GETSURROUNDING:
2663     {
2664       retrieveText = true;
2665       retrieveCursor = true;
2666       break;
2667     }
2668     case ImfManager::PRIVATECOMMAND:
2669     {
2670       // PRIVATECOMMAND event is just for getting the private command message
2671       retrieveText = true;
2672       retrieveCursor = true;
2673       break;
2674     }
2675     case ImfManager::VOID:
2676     {
2677       // do nothing
2678       break;
2679     }
2680   } // end switch
2681
2682   if( requestRelayout )
2683   {
2684     mImpl->mOperationsPending = ALL_OPERATIONS;
2685     mImpl->RequestRelayout();
2686   }
2687
2688   std::string text;
2689   CharacterIndex cursorPosition = 0u;
2690   Length numberOfWhiteSpaces = 0u;
2691
2692   if( retrieveCursor )
2693   {
2694     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2695
2696     cursorPosition = mImpl->GetLogicalCursorPosition();
2697
2698     if( cursorPosition < numberOfWhiteSpaces )
2699     {
2700       cursorPosition = 0u;
2701     }
2702     else
2703     {
2704       cursorPosition -= numberOfWhiteSpaces;
2705     }
2706   }
2707
2708   if( retrieveText )
2709   {
2710     mImpl->GetText( numberOfWhiteSpaces, text );
2711   }
2712
2713   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2714
2715   if( requestRelayout &&
2716       ( NULL != mImpl->mEditableControlInterface ) )
2717   {
2718     // Do this last since it provides callbacks into application code
2719     mImpl->mEditableControlInterface->TextChanged();
2720   }
2721
2722   return callbackData;
2723 }
2724
2725 void Controller::PasteClipboardItemEvent()
2726 {
2727   // Retrieve the clipboard contents first
2728   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2729   std::string stringToPaste( notifier.GetContent() );
2730
2731   // Commit the current pre-edit text; the contents of the clipboard should be appended
2732   mImpl->ResetImfManager();
2733
2734   // Temporary disable hiding clipboard
2735   mImpl->SetClipboardHideEnable( false );
2736
2737   // Paste
2738   PasteText( stringToPaste );
2739
2740   mImpl->SetClipboardHideEnable( true );
2741 }
2742
2743 // protected : Inherit from Text::Decorator::ControllerInterface.
2744
2745 void Controller::GetTargetSize( Vector2& targetSize )
2746 {
2747   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2748 }
2749
2750 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2751 {
2752   if( NULL != mImpl->mEditableControlInterface )
2753   {
2754     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2755   }
2756 }
2757
2758 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2759 {
2760   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2761
2762   if( NULL != mImpl->mEventData )
2763   {
2764     switch( handleType )
2765     {
2766       case GRAB_HANDLE:
2767       {
2768         Event event( Event::GRAB_HANDLE_EVENT );
2769         event.p1.mUint  = state;
2770         event.p2.mFloat = x;
2771         event.p3.mFloat = y;
2772
2773         mImpl->mEventData->mEventQueue.push_back( event );
2774         break;
2775       }
2776       case LEFT_SELECTION_HANDLE:
2777       {
2778         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2779         event.p1.mUint  = state;
2780         event.p2.mFloat = x;
2781         event.p3.mFloat = y;
2782
2783         mImpl->mEventData->mEventQueue.push_back( event );
2784         break;
2785       }
2786       case RIGHT_SELECTION_HANDLE:
2787       {
2788         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2789         event.p1.mUint  = state;
2790         event.p2.mFloat = x;
2791         event.p3.mFloat = y;
2792
2793         mImpl->mEventData->mEventQueue.push_back( event );
2794         break;
2795       }
2796       case LEFT_SELECTION_HANDLE_MARKER:
2797       case RIGHT_SELECTION_HANDLE_MARKER:
2798       {
2799         // Markers do not move the handles.
2800         break;
2801       }
2802       case HANDLE_TYPE_COUNT:
2803       {
2804         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2805       }
2806     }
2807
2808     mImpl->RequestRelayout();
2809   }
2810 }
2811
2812 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2813
2814 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2815 {
2816   if( NULL == mImpl->mEventData )
2817   {
2818     return;
2819   }
2820
2821   switch( button )
2822   {
2823     case Toolkit::TextSelectionPopup::CUT:
2824     {
2825       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2826       mImpl->mOperationsPending = ALL_OPERATIONS;
2827
2828       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2829           !mImpl->IsPlaceholderAvailable() )
2830       {
2831         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2832       }
2833       else
2834       {
2835         ShowPlaceholderText();
2836       }
2837
2838       mImpl->mEventData->mUpdateCursorPosition = true;
2839       mImpl->mEventData->mScrollAfterDelete = true;
2840
2841       mImpl->RequestRelayout();
2842
2843       if( NULL != mImpl->mEditableControlInterface )
2844       {
2845         mImpl->mEditableControlInterface->TextChanged();
2846       }
2847       break;
2848     }
2849     case Toolkit::TextSelectionPopup::COPY:
2850     {
2851       mImpl->SendSelectionToClipboard( false ); // Text not modified
2852
2853       mImpl->mEventData->mUpdateCursorPosition = true;
2854
2855       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2856       break;
2857     }
2858     case Toolkit::TextSelectionPopup::PASTE:
2859     {
2860       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2861       break;
2862     }
2863     case Toolkit::TextSelectionPopup::SELECT:
2864     {
2865       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2866
2867       if( mImpl->mEventData->mSelectionEnabled )
2868       {
2869         // Creates a SELECT event.
2870         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2871       }
2872       break;
2873     }
2874     case Toolkit::TextSelectionPopup::SELECT_ALL:
2875     {
2876       // Creates a SELECT_ALL event
2877       SelectEvent( 0.f, 0.f, true );
2878       break;
2879     }
2880     case Toolkit::TextSelectionPopup::CLIPBOARD:
2881     {
2882       mImpl->ShowClipboard();
2883       break;
2884     }
2885     case Toolkit::TextSelectionPopup::NONE:
2886     {
2887       // Nothing to do.
2888       break;
2889     }
2890   }
2891 }
2892
2893 void Controller::DisplayTimeExpired()
2894 {
2895   mImpl->mEventData->mUpdateCursorPosition = true;
2896   // Apply modifications to the model
2897   mImpl->mOperationsPending = ALL_OPERATIONS;
2898
2899   mImpl->RequestRelayout();
2900 }
2901
2902 // private : Update.
2903
2904 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2905 {
2906   bool removedPrevious = false;
2907   bool removedSelected = false;
2908   bool maxLengthReached = false;
2909
2910   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2911
2912   if( NULL == mImpl->mEventData )
2913   {
2914     return;
2915   }
2916
2917   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2918                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2919                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2920
2921   // TODO: At the moment the underline runs are only for pre-edit.
2922   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2923
2924   // Remove the previous IMF pre-edit.
2925   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2926   {
2927     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2928                                   mImpl->mEventData->mPreEditLength,
2929                                   DONT_UPDATE_INPUT_STYLE );
2930
2931     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2932     mImpl->mEventData->mPreEditLength = 0u;
2933   }
2934   else
2935   {
2936     // Remove the previous Selection.
2937     removedSelected = RemoveSelectedText();
2938
2939   }
2940
2941   Vector<Character> utf32Characters;
2942   Length characterCount = 0u;
2943
2944   if( !text.empty() )
2945   {
2946     //  Convert text into UTF-32
2947     utf32Characters.Resize( text.size() );
2948
2949     // This is a bit horrible but std::string returns a (signed) char*
2950     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2951
2952     // Transform a text array encoded in utf8 into an array encoded in utf32.
2953     // It returns the actual number of characters.
2954     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2955     utf32Characters.Resize( characterCount );
2956
2957     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2958     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2959   }
2960
2961   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2962   {
2963     // The placeholder text is no longer needed
2964     if( mImpl->IsShowingPlaceholderText() )
2965     {
2966       ResetText();
2967     }
2968
2969     mImpl->ChangeState( EventData::EDITING );
2970
2971     // Handle the IMF (predicitive text) state changes
2972     if( COMMIT == type )
2973     {
2974       // IMF manager is no longer handling key-events
2975       mImpl->ClearPreEditFlag();
2976     }
2977     else // PRE_EDIT
2978     {
2979       if( !mImpl->mEventData->mPreEditFlag )
2980       {
2981         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2982
2983         // Record the start of the pre-edit text
2984         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2985       }
2986
2987       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2988       mImpl->mEventData->mPreEditFlag = true;
2989
2990       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2991     }
2992
2993     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2994
2995     // Restrict new text to fit within Maximum characters setting.
2996     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2997     maxLengthReached = ( characterCount > maxSizeOfNewText );
2998
2999     // The cursor position.
3000     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3001
3002     // Update the text's style.
3003
3004     // Updates the text style runs by adding characters.
3005     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
3006
3007     // Get the character index from the cursor index.
3008     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
3009
3010     // Retrieve the text's style for the given index.
3011     InputStyle style;
3012     mImpl->RetrieveDefaultInputStyle( style );
3013     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3014
3015     // Whether to add a new text color run.
3016     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
3017
3018     // Whether to add a new font run.
3019     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
3020     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
3021     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
3022     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
3023     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
3024
3025     // Add style runs.
3026     if( addColorRun )
3027     {
3028       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3029       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3030
3031       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3032       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3033       colorRun.characterRun.characterIndex = cursorIndex;
3034       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3035     }
3036
3037     if( addFontNameRun   ||
3038         addFontWeightRun ||
3039         addFontWidthRun  ||
3040         addFontSlantRun  ||
3041         addFontSizeRun )
3042     {
3043       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3044       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3045
3046       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3047
3048       if( addFontNameRun )
3049       {
3050         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3051         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3052         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3053         fontDescriptionRun.familyDefined = true;
3054
3055         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3056       }
3057
3058       if( addFontWeightRun )
3059       {
3060         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3061         fontDescriptionRun.weightDefined = true;
3062       }
3063
3064       if( addFontWidthRun )
3065       {
3066         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3067         fontDescriptionRun.widthDefined = true;
3068       }
3069
3070       if( addFontSlantRun )
3071       {
3072         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3073         fontDescriptionRun.slantDefined = true;
3074       }
3075
3076       if( addFontSizeRun )
3077       {
3078         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3079         fontDescriptionRun.sizeDefined = true;
3080       }
3081
3082       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3083       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3084     }
3085
3086     // Insert at current cursor position.
3087     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3088
3089     if( cursorIndex < numberOfCharactersInModel )
3090     {
3091       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3092     }
3093     else
3094     {
3095       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3096     }
3097
3098     // Mark the first paragraph to be updated.
3099     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3100     {
3101       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3102       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3103       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3104       mImpl->mTextUpdateInfo.mClearAll = true;
3105     }
3106     else
3107     {
3108       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3109       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3110     }
3111
3112     // Update the cursor index.
3113     cursorIndex += maxSizeOfNewText;
3114
3115     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 );
3116   }
3117
3118   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3119       mImpl->IsPlaceholderAvailable() )
3120   {
3121     // Show place-holder if empty after removing the pre-edit text
3122     ShowPlaceholderText();
3123     mImpl->mEventData->mUpdateCursorPosition = true;
3124     mImpl->ClearPreEditFlag();
3125   }
3126   else if( removedPrevious ||
3127            removedSelected ||
3128            ( 0 != utf32Characters.Count() ) )
3129   {
3130     // Queue an inserted event
3131     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3132
3133     mImpl->mEventData->mUpdateCursorPosition = true;
3134     if( removedSelected )
3135     {
3136       mImpl->mEventData->mScrollAfterDelete = true;
3137     }
3138     else
3139     {
3140       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3141     }
3142   }
3143
3144   if( maxLengthReached )
3145   {
3146     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3147
3148     mImpl->ResetImfManager();
3149
3150     if( NULL != mImpl->mEditableControlInterface )
3151     {
3152       // Do this last since it provides callbacks into application code
3153       mImpl->mEditableControlInterface->MaxLengthReached();
3154     }
3155   }
3156 }
3157
3158 void Controller::PasteText( const std::string& stringToPaste )
3159 {
3160   InsertText( stringToPaste, Text::Controller::COMMIT );
3161   mImpl->ChangeState( EventData::EDITING );
3162   mImpl->RequestRelayout();
3163
3164   if( NULL != mImpl->mEditableControlInterface )
3165   {
3166     // Do this last since it provides callbacks into application code
3167     mImpl->mEditableControlInterface->TextChanged();
3168   }
3169 }
3170
3171 bool Controller::RemoveText( int cursorOffset,
3172                              int numberOfCharacters,
3173                              UpdateInputStyleType type )
3174 {
3175   bool removed = false;
3176
3177   if( NULL == mImpl->mEventData )
3178   {
3179     return removed;
3180   }
3181
3182   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3183                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3184
3185   if( !mImpl->IsShowingPlaceholderText() )
3186   {
3187     // Delete at current cursor position
3188     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3189     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3190
3191     CharacterIndex cursorIndex = 0;
3192
3193     // Validate the cursor position & number of characters
3194     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3195     {
3196       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3197     }
3198
3199     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3200     {
3201       numberOfCharacters = currentText.Count() - cursorIndex;
3202     }
3203
3204     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.
3205         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
3206     {
3207       // Mark the paragraphs to be updated.
3208       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3209       {
3210         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3211         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3212         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3213         mImpl->mTextUpdateInfo.mClearAll = true;
3214       }
3215       else
3216       {
3217         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3218         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3219       }
3220
3221       // Update the input style and remove the text's style before removing the text.
3222
3223       if( UPDATE_INPUT_STYLE == type )
3224       {
3225         // Keep a copy of the current input style.
3226         InputStyle currentInputStyle;
3227         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3228
3229         // Set first the default input style.
3230         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3231
3232         // Update the input style.
3233         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3234
3235         // Compare if the input style has changed.
3236         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3237
3238         if( hasInputStyleChanged )
3239         {
3240           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3241           // Queue the input style changed signal.
3242           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3243         }
3244       }
3245
3246       // Updates the text style runs by removing characters. Runs with no characters are removed.
3247       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3248
3249       // Remove the characters.
3250       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3251       Vector<Character>::Iterator last  = first + numberOfCharacters;
3252
3253       currentText.Erase( first, last );
3254
3255       // Cursor position retreat
3256       oldCursorIndex = cursorIndex;
3257
3258       mImpl->mEventData->mScrollAfterDelete = true;
3259
3260       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3261       removed = true;
3262     }
3263   }
3264
3265   return removed;
3266 }
3267
3268 bool Controller::RemoveSelectedText()
3269 {
3270   bool textRemoved( false );
3271
3272   if( EventData::SELECTING == mImpl->mEventData->mState )
3273   {
3274     std::string removedString;
3275     mImpl->RetrieveSelection( removedString, true );
3276
3277     if( !removedString.empty() )
3278     {
3279       textRemoved = true;
3280       mImpl->ChangeState( EventData::EDITING );
3281     }
3282   }
3283
3284   return textRemoved;
3285 }
3286
3287 // private : Relayout.
3288
3289 bool Controller::DoRelayout( const Size& size,
3290                              OperationsMask operationsRequired,
3291                              Size& layoutSize )
3292 {
3293   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3294   bool viewUpdated( false );
3295
3296   // Calculate the operations to be done.
3297   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3298
3299   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3300   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3301
3302   // Get the current layout size.
3303   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3304
3305   if( NO_OPERATION != ( LAYOUT & operations ) )
3306   {
3307     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3308
3309     // Some vectors with data needed to layout and reorder may be void
3310     // after the first time the text has been laid out.
3311     // Fill the vectors again.
3312
3313     // Calculate the number of glyphs to layout.
3314     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3315     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3316     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3317     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3318
3319     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3320     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3321     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3322     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3323
3324     if( 0u == totalNumberOfGlyphs )
3325     {
3326       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3327       {
3328         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3329       }
3330
3331       // Nothing else to do if there is no glyphs.
3332       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3333       return true;
3334     }
3335
3336     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3337     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3338     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3339     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3340     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3341     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3342     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3343     float outlineWidth = mImpl->mModel->GetOutlineWidth();
3344
3345     // Set the layout parameters.
3346     Layout::Parameters layoutParameters( size,
3347                                          textBuffer,
3348                                          lineBreakInfo.Begin(),
3349                                          wordBreakInfo.Begin(),
3350                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3351                                          glyphs.Begin(),
3352                                          glyphsToCharactersMap.Begin(),
3353                                          charactersPerGlyph.Begin(),
3354                                          charactersToGlyphBuffer,
3355                                          glyphsPerCharacterBuffer,
3356                                          totalNumberOfGlyphs,
3357                                          mImpl->mModel->mHorizontalAlignment,
3358                                          mImpl->mModel->mLineWrapMode,
3359                                          outlineWidth );
3360
3361     // Resize the vector of positions to have the same size than the vector of glyphs.
3362     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3363     glyphPositions.Resize( totalNumberOfGlyphs );
3364
3365     // Whether the last character is a new paragraph character.
3366     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3367     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3368
3369     // The initial glyph and the number of glyphs to layout.
3370     layoutParameters.startGlyphIndex = startGlyphIndex;
3371     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3372     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3373     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3374
3375     // Update the ellipsis
3376     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3377
3378     if( NULL != mImpl->mEventData )
3379     {
3380       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3381       {
3382         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3383       }
3384       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3385       {
3386         // Disable ellipsis when editing
3387         elideTextEnabled = false;
3388       }
3389
3390       // Reset the scroll position in inactive state
3391       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3392       {
3393         ResetScrollPosition();
3394       }
3395     }
3396
3397     // Update the visual model.
3398     Size newLayoutSize;
3399     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3400                                                    glyphPositions,
3401                                                    mImpl->mModel->mVisualModel->mLines,
3402                                                    newLayoutSize,
3403                                                    elideTextEnabled );
3404
3405     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3406
3407     if( viewUpdated )
3408     {
3409       layoutSize = newLayoutSize;
3410
3411       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3412       {
3413         mImpl->mAutoScrollDirectionRTL = false;
3414       }
3415
3416       // Reorder the lines
3417       if( NO_OPERATION != ( REORDER & operations ) )
3418       {
3419         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3420         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3421
3422         // Check first if there are paragraphs with bidirectional info.
3423         if( 0u != bidirectionalInfo.Count() )
3424         {
3425           // Get the lines
3426           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3427
3428           // Reorder the lines.
3429           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3430           ReorderLines( bidirectionalInfo,
3431                         startIndex,
3432                         requestedNumberOfCharacters,
3433                         mImpl->mModel->mVisualModel->mLines,
3434                         bidirectionalLineInfo );
3435
3436           // Set the bidirectional info per line into the layout parameters.
3437           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3438           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3439
3440           // Re-layout the text. Reorder those lines with right to left characters.
3441           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3442                                                          startIndex,
3443                                                          requestedNumberOfCharacters,
3444                                                          glyphPositions );
3445
3446           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3447           {
3448             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3449             if ( firstline )
3450             {
3451               mImpl->mAutoScrollDirectionRTL = firstline->direction;
3452             }
3453           }
3454         }
3455       } // REORDER
3456
3457       // Sets the layout size.
3458       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3459       {
3460         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3461       }
3462     } // view updated
3463   }
3464
3465   if( NO_OPERATION != ( ALIGN & operations ) )
3466   {
3467     // The laid-out lines.
3468     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3469
3470     // Need to align with the control's size as the text may contain lines
3471     // starting either with left to right text or right to left.
3472     mImpl->mLayoutEngine.Align( size,
3473                                 startIndex,
3474                                 requestedNumberOfCharacters,
3475                                 mImpl->mModel->mHorizontalAlignment,
3476                                 lines,
3477                                 mImpl->mModel->mAlignmentOffset );
3478
3479     viewUpdated = true;
3480   }
3481 #if defined(DEBUG_ENABLED)
3482   std::string currentText;
3483   GetText( currentText );
3484   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
3485 #endif
3486   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3487   return viewUpdated;
3488 }
3489
3490 void Controller::CalculateVerticalOffset( const Size& controlSize )
3491 {
3492   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3493
3494   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3495   {
3496     // Get the line height of the default font.
3497     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3498   }
3499
3500   switch( mImpl->mModel->mVerticalAlignment )
3501   {
3502     case VerticalAlignment::TOP:
3503     {
3504       mImpl->mModel->mScrollPosition.y = 0.f;
3505       break;
3506     }
3507     case VerticalAlignment::CENTER:
3508     {
3509       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3510       break;
3511     }
3512     case VerticalAlignment::BOTTOM:
3513     {
3514       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3515       break;
3516     }
3517   }
3518 }
3519
3520 // private : Events.
3521
3522 void Controller::ProcessModifyEvents()
3523 {
3524   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3525
3526   if( 0u == events.Count() )
3527   {
3528     // Nothing to do.
3529     return;
3530   }
3531
3532   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3533          endIt = events.End();
3534        it != endIt;
3535        ++it )
3536   {
3537     const ModifyEvent& event = *it;
3538
3539     if( ModifyEvent::TEXT_REPLACED == event.type )
3540     {
3541       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3542       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3543
3544       TextReplacedEvent();
3545     }
3546     else if( ModifyEvent::TEXT_INSERTED == event.type )
3547     {
3548       TextInsertedEvent();
3549     }
3550     else if( ModifyEvent::TEXT_DELETED == event.type )
3551     {
3552       // Placeholder-text cannot be deleted
3553       if( !mImpl->IsShowingPlaceholderText() )
3554       {
3555         TextDeletedEvent();
3556       }
3557     }
3558   }
3559
3560   if( NULL != mImpl->mEventData )
3561   {
3562     // When the text is being modified, delay cursor blinking
3563     mImpl->mEventData->mDecorator->DelayCursorBlink();
3564   }
3565
3566   // Discard temporary text
3567   events.Clear();
3568 }
3569
3570 void Controller::TextReplacedEvent()
3571 {
3572   // The natural size needs to be re-calculated.
3573   mImpl->mRecalculateNaturalSize = true;
3574
3575   // Apply modifications to the model
3576   mImpl->mOperationsPending = ALL_OPERATIONS;
3577 }
3578
3579 void Controller::TextInsertedEvent()
3580 {
3581   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3582
3583   if( NULL == mImpl->mEventData )
3584   {
3585     return;
3586   }
3587
3588   mImpl->mEventData->mCheckScrollAmount = true;
3589
3590   // The natural size needs to be re-calculated.
3591   mImpl->mRecalculateNaturalSize = true;
3592
3593   // Apply modifications to the model; TODO - Optimize this
3594   mImpl->mOperationsPending = ALL_OPERATIONS;
3595 }
3596
3597 void Controller::TextDeletedEvent()
3598 {
3599   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3600
3601   if( NULL == mImpl->mEventData )
3602   {
3603     return;
3604   }
3605
3606   mImpl->mEventData->mCheckScrollAmount = true;
3607
3608   // The natural size needs to be re-calculated.
3609   mImpl->mRecalculateNaturalSize = true;
3610
3611   // Apply modifications to the model; TODO - Optimize this
3612   mImpl->mOperationsPending = ALL_OPERATIONS;
3613 }
3614
3615 void Controller::SelectEvent( float x, float y, bool selectAll )
3616 {
3617   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3618
3619   if( NULL != mImpl->mEventData )
3620   {
3621     if( selectAll )
3622     {
3623       Event event( Event::SELECT_ALL );
3624       mImpl->mEventData->mEventQueue.push_back( event );
3625     }
3626     else
3627     {
3628       Event event( Event::SELECT );
3629       event.p2.mFloat = x;
3630       event.p3.mFloat = y;
3631       mImpl->mEventData->mEventQueue.push_back( event );
3632     }
3633
3634     mImpl->mEventData->mCheckScrollAmount = true;
3635     mImpl->mEventData->mIsLeftHandleSelected = true;
3636     mImpl->mEventData->mIsRightHandleSelected = true;
3637     mImpl->RequestRelayout();
3638   }
3639 }
3640
3641 bool Controller::DeleteEvent( int keyCode )
3642 {
3643   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
3644
3645   bool removed = false;
3646
3647   if( NULL == mImpl->mEventData )
3648   {
3649     return removed;
3650   }
3651
3652   // IMF manager is no longer handling key-events
3653   mImpl->ClearPreEditFlag();
3654
3655   if( EventData::SELECTING == mImpl->mEventData->mState )
3656   {
3657     removed = RemoveSelectedText();
3658   }
3659   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
3660   {
3661     // Remove the character before the current cursor position
3662     removed = RemoveText( -1,
3663                           1,
3664                           UPDATE_INPUT_STYLE );
3665   }
3666   else if( ( mImpl->mEventData->mPrimaryCursorPosition >= 0 ) && ( keyCode == Dali::DevelKey::DALI_KEY_DELETE ) )
3667   {
3668     // Remove the character after the current cursor position
3669     removed = RemoveText( 0,
3670                           1,
3671                           UPDATE_INPUT_STYLE );
3672   }
3673
3674   if( removed )
3675   {
3676     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3677         !mImpl->IsPlaceholderAvailable() )
3678     {
3679       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3680     }
3681     else
3682     {
3683       ShowPlaceholderText();
3684     }
3685     mImpl->mEventData->mUpdateCursorPosition = true;
3686     mImpl->mEventData->mScrollAfterDelete = true;
3687   }
3688
3689   return removed;
3690 }
3691
3692 // private : Helpers.
3693
3694 void Controller::ResetText()
3695 {
3696   // Reset buffers.
3697   mImpl->mModel->mLogicalModel->mText.Clear();
3698
3699   // We have cleared everything including the placeholder-text
3700   mImpl->PlaceholderCleared();
3701
3702   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3703   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3704   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3705
3706   // Clear any previous text.
3707   mImpl->mTextUpdateInfo.mClearAll = true;
3708
3709   // The natural size needs to be re-calculated.
3710   mImpl->mRecalculateNaturalSize = true;
3711
3712   // Apply modifications to the model
3713   mImpl->mOperationsPending = ALL_OPERATIONS;
3714 }
3715
3716 void Controller::ShowPlaceholderText()
3717 {
3718   if( mImpl->IsPlaceholderAvailable() )
3719   {
3720     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3721
3722     if( NULL == mImpl->mEventData )
3723     {
3724       return;
3725     }
3726
3727     mImpl->mEventData->mIsShowingPlaceholderText = true;
3728
3729     // Disable handles when showing place-holder text
3730     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3731     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3732     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3733
3734     const char* text( NULL );
3735     size_t size( 0 );
3736
3737     // TODO - Switch Placeholder text when changing state
3738     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3739         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3740     {
3741       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3742       size = mImpl->mEventData->mPlaceholderTextActive.size();
3743     }
3744     else
3745     {
3746       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3747       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3748     }
3749
3750     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3751     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3752
3753     // Reset model for showing placeholder.
3754     mImpl->mModel->mLogicalModel->mText.Clear();
3755     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3756
3757     // Convert text into UTF-32
3758     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3759     utf32Characters.Resize( size );
3760
3761     // This is a bit horrible but std::string returns a (signed) char*
3762     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3763
3764     // Transform a text array encoded in utf8 into an array encoded in utf32.
3765     // It returns the actual number of characters.
3766     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3767     utf32Characters.Resize( characterCount );
3768
3769     // The characters to be added.
3770     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3771
3772     // Reset the cursor position
3773     mImpl->mEventData->mPrimaryCursorPosition = 0;
3774
3775     // The natural size needs to be re-calculated.
3776     mImpl->mRecalculateNaturalSize = true;
3777
3778     // Apply modifications to the model
3779     mImpl->mOperationsPending = ALL_OPERATIONS;
3780
3781     // Update the rest of the model during size negotiation
3782     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3783   }
3784 }
3785
3786 void Controller::ClearFontData()
3787 {
3788   if( mImpl->mFontDefaults )
3789   {
3790     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3791   }
3792
3793   // Set flags to update the model.
3794   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3795   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3796   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3797
3798   mImpl->mTextUpdateInfo.mClearAll = true;
3799   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3800   mImpl->mRecalculateNaturalSize = true;
3801
3802   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3803                                                            VALIDATE_FONTS            |
3804                                                            SHAPE_TEXT                |
3805                                                            GET_GLYPH_METRICS         |
3806                                                            LAYOUT                    |
3807                                                            UPDATE_LAYOUT_SIZE        |
3808                                                            REORDER                   |
3809                                                            ALIGN );
3810 }
3811
3812 void Controller::ClearStyleData()
3813 {
3814   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3815   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3816 }
3817
3818 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3819 {
3820   // Reset the cursor position
3821   if( NULL != mImpl->mEventData )
3822   {
3823     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3824
3825     // Update the cursor if it's in editing mode.
3826     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3827     {
3828       mImpl->mEventData->mUpdateCursorPosition = true;
3829     }
3830   }
3831 }
3832
3833 void Controller::ResetScrollPosition()
3834 {
3835   if( NULL != mImpl->mEventData )
3836   {
3837     // Reset the scroll position.
3838     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3839     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3840   }
3841 }
3842
3843 void Controller::SetControlInterface( ControlInterface* controlInterface )
3844 {
3845   mImpl->mControlInterface = controlInterface;
3846 }
3847
3848 bool Controller::ShouldClearFocusOnEscape() const
3849 {
3850   return mImpl->mShouldClearFocusOnEscape;
3851 }
3852
3853 // private : Private contructors & copy operator.
3854
3855 Controller::Controller()
3856 : mImpl( NULL )
3857 {
3858   mImpl = new Controller::Impl( NULL, NULL );
3859 }
3860
3861 Controller::Controller( ControlInterface* controlInterface )
3862 {
3863   mImpl = new Controller::Impl( controlInterface, NULL );
3864 }
3865
3866 Controller::Controller( ControlInterface* controlInterface,
3867                         EditableControlInterface* editableControlInterface )
3868 {
3869   mImpl = new Controller::Impl( controlInterface,
3870                                 editableControlInterface );
3871 }
3872
3873 // The copy constructor and operator are left unimplemented.
3874
3875 // protected : Destructor.
3876
3877 Controller::~Controller()
3878 {
3879   delete mImpl;
3880 }
3881
3882 } // namespace Text
3883
3884 } // namespace Toolkit
3885
3886 } // namespace Dali