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