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