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