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