Merge "use string_view to avoid temporary string allocation." into devel/master
[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       if (!IsEditable()) return false;
2979
2980       if( !keyString.empty() )
2981       {
2982         // InputMethodContext is no longer handling key-events
2983         mImpl->ClearPreEditFlag();
2984
2985         InsertText( keyString, COMMIT );
2986
2987         textChanged = true;
2988
2989         // Will request for relayout.
2990         relayoutNeeded = true;
2991       }
2992
2993     }
2994
2995     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2996          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2997          ( !isNullKey ) &&
2998          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2999          ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) &&
3000          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
3001          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
3002     {
3003       // Should not change the state if the key is the shift send by the InputMethodContext.
3004       // Otherwise, when the state is SELECTING the text controller can't send the right
3005       // surrounding info to the InputMethodContext.
3006       mImpl->ChangeState( EventData::EDITING );
3007
3008       // Will request for relayout.
3009       relayoutNeeded = true;
3010     }
3011
3012     if( relayoutNeeded )
3013     {
3014       mImpl->RequestRelayout();
3015     }
3016   }
3017
3018   if( textChanged &&
3019       ( NULL != mImpl->mEditableControlInterface ) )
3020   {
3021     // Do this last since it provides callbacks into application code
3022     mImpl->mEditableControlInterface->TextChanged();
3023   }
3024
3025   return true;
3026 }
3027
3028 void Controller::TapEvent( unsigned int tapCount, float x, float y )
3029 {
3030   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
3031
3032   if( NULL != mImpl->mEventData )
3033   {
3034     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
3035     EventData::State state( mImpl->mEventData->mState );
3036     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
3037
3038     if( mImpl->IsClipboardVisible() )
3039     {
3040       if( EventData::INACTIVE == state || EventData::EDITING == state)
3041       {
3042         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
3043       }
3044       relayoutNeeded = true;
3045     }
3046     else if( 1u == tapCount )
3047     {
3048       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
3049       {
3050         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
3051       }
3052
3053       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
3054       {
3055         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
3056         relayoutNeeded = true;
3057       }
3058       else
3059       {
3060         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
3061         {
3062           // Hide placeholder text
3063           ResetText();
3064         }
3065
3066         if( EventData::INACTIVE == state )
3067         {
3068           mImpl->ChangeState( EventData::EDITING );
3069         }
3070         else if( !mImpl->IsClipboardEmpty() )
3071         {
3072           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
3073         }
3074         relayoutNeeded = true;
3075       }
3076     }
3077     else if( 2u == tapCount )
3078     {
3079       if( mImpl->mEventData->mSelectionEnabled &&
3080           mImpl->IsShowingRealText() )
3081       {
3082         relayoutNeeded = true;
3083         mImpl->mEventData->mIsLeftHandleSelected = true;
3084         mImpl->mEventData->mIsRightHandleSelected = true;
3085       }
3086     }
3087
3088     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
3089     if( relayoutNeeded )
3090     {
3091       Event event( Event::TAP_EVENT );
3092       event.p1.mUint = tapCount;
3093       event.p2.mFloat = x;
3094       event.p3.mFloat = y;
3095       mImpl->mEventData->mEventQueue.push_back( event );
3096
3097       mImpl->RequestRelayout();
3098     }
3099   }
3100
3101   // Reset keyboard as tap event has occurred.
3102   mImpl->ResetInputMethodContext();
3103 }
3104
3105 void Controller::PanEvent( GestureState state, const Vector2& displacement )
3106 {
3107   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
3108
3109   if( NULL != mImpl->mEventData )
3110   {
3111     Event event( Event::PAN_EVENT );
3112     event.p1.mInt = static_cast<int>( state );
3113     event.p2.mFloat = displacement.x;
3114     event.p3.mFloat = displacement.y;
3115     mImpl->mEventData->mEventQueue.push_back( event );
3116
3117     mImpl->RequestRelayout();
3118   }
3119 }
3120
3121 void Controller::LongPressEvent( GestureState state, float x, float y  )
3122 {
3123   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
3124
3125   if( ( state == GestureState::STARTED ) &&
3126       ( NULL != mImpl->mEventData ) )
3127   {
3128     // The 1st long-press on inactive text-field is treated as tap
3129     if( EventData::INACTIVE == mImpl->mEventData->mState )
3130     {
3131       mImpl->ChangeState( EventData::EDITING );
3132
3133       Event event( Event::TAP_EVENT );
3134       event.p1.mUint = 1;
3135       event.p2.mFloat = x;
3136       event.p3.mFloat = y;
3137       mImpl->mEventData->mEventQueue.push_back( event );
3138
3139       mImpl->RequestRelayout();
3140     }
3141     else if( !mImpl->IsShowingRealText() )
3142     {
3143       Event event( Event::LONG_PRESS_EVENT );
3144       event.p1.mInt = static_cast<int>( state );
3145       event.p2.mFloat = x;
3146       event.p3.mFloat = y;
3147       mImpl->mEventData->mEventQueue.push_back( event );
3148       mImpl->RequestRelayout();
3149     }
3150     else if( !mImpl->IsClipboardVisible() )
3151     {
3152       // Reset the InputMethodContext to commit the pre-edit before selecting the text.
3153       mImpl->ResetInputMethodContext();
3154
3155       Event event( Event::LONG_PRESS_EVENT );
3156       event.p1.mInt = static_cast<int>( state );
3157       event.p2.mFloat = x;
3158       event.p3.mFloat = y;
3159       mImpl->mEventData->mEventQueue.push_back( event );
3160       mImpl->RequestRelayout();
3161
3162       mImpl->mEventData->mIsLeftHandleSelected = true;
3163       mImpl->mEventData->mIsRightHandleSelected = true;
3164     }
3165   }
3166 }
3167
3168 void Controller::SelectEvent( float x, float y, SelectionType selectType )
3169 {
3170   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3171
3172   if( NULL != mImpl->mEventData )
3173   {
3174     if( selectType == SelectionType::ALL )
3175     {
3176       Event event( Event::SELECT_ALL );
3177       mImpl->mEventData->mEventQueue.push_back( event );
3178     }
3179     else if( selectType == SelectionType::NONE )
3180     {
3181       Event event( Event::SELECT_NONE );
3182       mImpl->mEventData->mEventQueue.push_back( event );
3183     }
3184     else
3185     {
3186       Event event( Event::SELECT );
3187       event.p2.mFloat = x;
3188       event.p3.mFloat = y;
3189       mImpl->mEventData->mEventQueue.push_back( event );
3190     }
3191
3192     mImpl->mEventData->mCheckScrollAmount = true;
3193     mImpl->mEventData->mIsLeftHandleSelected = true;
3194     mImpl->mEventData->mIsRightHandleSelected = true;
3195     mImpl->RequestRelayout();
3196   }
3197 }
3198
3199 void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end)
3200 {
3201   if( mImpl->mEventData )
3202   {
3203     mImpl->mEventData->mCheckScrollAmount = true;
3204     mImpl->mEventData->mIsLeftHandleSelected = true;
3205     mImpl->mEventData->mIsRightHandleSelected = true;
3206     mImpl->SetTextSelectionRange(start, end);
3207     mImpl->RequestRelayout();
3208     KeyboardFocusGainEvent();
3209   }
3210 }
3211
3212 Uint32Pair Controller::GetTextSelectionRange() const
3213 {
3214   return mImpl->GetTextSelectionRange();
3215 }
3216
3217 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
3218 {
3219   // Whether the text needs to be relaid-out.
3220   bool requestRelayout = false;
3221
3222   // Whether to retrieve the text and cursor position to be sent to the InputMethodContext.
3223   bool retrieveText = false;
3224   bool retrieveCursor = false;
3225
3226   switch( inputMethodContextEvent.eventName )
3227   {
3228     case InputMethodContext::COMMIT:
3229     {
3230       InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT );
3231       requestRelayout = true;
3232       retrieveCursor = true;
3233       break;
3234     }
3235     case InputMethodContext::PRE_EDIT:
3236     {
3237       InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT );
3238       requestRelayout = true;
3239       retrieveCursor = true;
3240       break;
3241     }
3242     case InputMethodContext::DELETE_SURROUNDING:
3243     {
3244       const bool textDeleted = RemoveText( inputMethodContextEvent.cursorOffset,
3245                                            inputMethodContextEvent.numberOfChars,
3246                                            DONT_UPDATE_INPUT_STYLE );
3247
3248       if( textDeleted )
3249       {
3250         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3251             !mImpl->IsPlaceholderAvailable() )
3252         {
3253           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3254         }
3255         else
3256         {
3257           ShowPlaceholderText();
3258         }
3259         mImpl->mEventData->mUpdateCursorPosition = true;
3260         mImpl->mEventData->mScrollAfterDelete = true;
3261
3262         requestRelayout = true;
3263       }
3264       break;
3265     }
3266     case InputMethodContext::GET_SURROUNDING:
3267     {
3268       retrieveText = true;
3269       retrieveCursor = true;
3270       break;
3271     }
3272     case InputMethodContext::PRIVATE_COMMAND:
3273     {
3274       // PRIVATECOMMAND event is just for getting the private command message
3275       retrieveText = true;
3276       retrieveCursor = true;
3277       break;
3278     }
3279     case InputMethodContext::VOID:
3280     {
3281       // do nothing
3282       break;
3283     }
3284   } // end switch
3285
3286   if( requestRelayout )
3287   {
3288     mImpl->mOperationsPending = ALL_OPERATIONS;
3289     mImpl->RequestRelayout();
3290   }
3291
3292   std::string text;
3293   CharacterIndex cursorPosition = 0u;
3294   Length numberOfWhiteSpaces = 0u;
3295
3296   if( retrieveCursor )
3297   {
3298     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
3299
3300     cursorPosition = mImpl->GetLogicalCursorPosition();
3301
3302     if( cursorPosition < numberOfWhiteSpaces )
3303     {
3304       cursorPosition = 0u;
3305     }
3306     else
3307     {
3308       cursorPosition -= numberOfWhiteSpaces;
3309     }
3310   }
3311
3312   if( retrieveText )
3313   {
3314     if( !mImpl->IsShowingPlaceholderText() )
3315     {
3316       // Retrieves the normal text string.
3317       mImpl->GetText( numberOfWhiteSpaces, text );
3318     }
3319     else
3320     {
3321       // When the current text is Placeholder Text, the surrounding text should be empty string.
3322       // It means DALi should send empty string ("") to IME.
3323       text = "";
3324     }
3325   }
3326
3327   InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
3328
3329   if( requestRelayout &&
3330       ( NULL != mImpl->mEditableControlInterface ) )
3331   {
3332     // Do this last since it provides callbacks into application code
3333     mImpl->mEditableControlInterface->TextChanged();
3334   }
3335
3336   return callbackData;
3337 }
3338
3339 void Controller::PasteClipboardItemEvent()
3340 {
3341   // Retrieve the clipboard contents first
3342   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
3343   std::string stringToPaste( notifier.GetContent() );
3344
3345   // Commit the current pre-edit text; the contents of the clipboard should be appended
3346   mImpl->ResetInputMethodContext();
3347
3348   // Temporary disable hiding clipboard
3349   mImpl->SetClipboardHideEnable( false );
3350
3351   // Paste
3352   PasteText( stringToPaste );
3353
3354   mImpl->SetClipboardHideEnable( true );
3355 }
3356
3357 // protected : Inherit from Text::Decorator::ControllerInterface.
3358
3359 void Controller::GetTargetSize( Vector2& targetSize )
3360 {
3361   targetSize = mImpl->mModel->mVisualModel->mControlSize;
3362 }
3363
3364 void Controller::AddDecoration( Actor& actor, bool needsClipping )
3365 {
3366   if( NULL != mImpl->mEditableControlInterface )
3367   {
3368     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
3369   }
3370 }
3371
3372 bool Controller::IsEditable() const
3373 {
3374   return mImpl->IsEditable();
3375 }
3376
3377 void Controller::SetEditable( bool editable )
3378 {
3379   mImpl->SetEditable( editable );
3380   if(mImpl->mEventData && mImpl->mEventData->mDecorator)
3381   {
3382     mImpl->mEventData->mDecorator->SetEditable( editable );
3383   }
3384 }
3385
3386 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
3387 {
3388   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
3389
3390   if( NULL != mImpl->mEventData )
3391   {
3392     switch( handleType )
3393     {
3394       case GRAB_HANDLE:
3395       {
3396         Event event( Event::GRAB_HANDLE_EVENT );
3397         event.p1.mUint  = state;
3398         event.p2.mFloat = x;
3399         event.p3.mFloat = y;
3400
3401         mImpl->mEventData->mEventQueue.push_back( event );
3402         break;
3403       }
3404       case LEFT_SELECTION_HANDLE:
3405       {
3406         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
3407         event.p1.mUint  = state;
3408         event.p2.mFloat = x;
3409         event.p3.mFloat = y;
3410
3411         mImpl->mEventData->mEventQueue.push_back( event );
3412         break;
3413       }
3414       case RIGHT_SELECTION_HANDLE:
3415       {
3416         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
3417         event.p1.mUint  = state;
3418         event.p2.mFloat = x;
3419         event.p3.mFloat = y;
3420
3421         mImpl->mEventData->mEventQueue.push_back( event );
3422         break;
3423       }
3424       case LEFT_SELECTION_HANDLE_MARKER:
3425       case RIGHT_SELECTION_HANDLE_MARKER:
3426       {
3427         // Markers do not move the handles.
3428         break;
3429       }
3430       case HANDLE_TYPE_COUNT:
3431       {
3432         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
3433       }
3434     }
3435
3436     mImpl->RequestRelayout();
3437   }
3438 }
3439
3440 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
3441
3442 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
3443 {
3444   if( NULL == mImpl->mEventData )
3445   {
3446     return;
3447   }
3448
3449   switch( button )
3450   {
3451     case Toolkit::TextSelectionPopup::CUT:
3452     {
3453       if (!IsEditable()) return;
3454       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
3455       mImpl->mOperationsPending = ALL_OPERATIONS;
3456
3457       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3458           !mImpl->IsPlaceholderAvailable() )
3459       {
3460         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3461       }
3462       else
3463       {
3464         ShowPlaceholderText();
3465       }
3466
3467       mImpl->mEventData->mUpdateCursorPosition = true;
3468       mImpl->mEventData->mScrollAfterDelete = true;
3469
3470       mImpl->RequestRelayout();
3471
3472       if( NULL != mImpl->mEditableControlInterface )
3473       {
3474         mImpl->mEditableControlInterface->TextChanged();
3475       }
3476       break;
3477     }
3478     case Toolkit::TextSelectionPopup::COPY:
3479     {
3480       mImpl->SendSelectionToClipboard( false ); // Text not modified
3481
3482       mImpl->mEventData->mUpdateCursorPosition = true;
3483
3484       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
3485       break;
3486     }
3487     case Toolkit::TextSelectionPopup::PASTE:
3488     {
3489       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
3490       break;
3491     }
3492     case Toolkit::TextSelectionPopup::SELECT:
3493     {
3494       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
3495
3496       if( mImpl->mEventData->mSelectionEnabled )
3497       {
3498         // Creates a SELECT event.
3499         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE );
3500       }
3501       break;
3502     }
3503     case Toolkit::TextSelectionPopup::SELECT_ALL:
3504     {
3505       // Creates a SELECT_ALL event
3506       SelectEvent( 0.f, 0.f, SelectionType::ALL );
3507       break;
3508     }
3509     case Toolkit::TextSelectionPopup::CLIPBOARD:
3510     {
3511       mImpl->ShowClipboard();
3512       break;
3513     }
3514     case Toolkit::TextSelectionPopup::NONE:
3515     {
3516       // Nothing to do.
3517       break;
3518     }
3519   }
3520 }
3521
3522 void Controller::DisplayTimeExpired()
3523 {
3524   mImpl->mEventData->mUpdateCursorPosition = true;
3525   // Apply modifications to the model
3526   mImpl->mOperationsPending = ALL_OPERATIONS;
3527
3528   mImpl->RequestRelayout();
3529 }
3530
3531 // private : Update.
3532
3533 void Controller::InsertText( const std::string& text, Controller::InsertType type )
3534 {
3535   bool removedPrevious = false;
3536   bool removedSelected = false;
3537   bool maxLengthReached = false;
3538
3539   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
3540
3541   if( NULL == mImpl->mEventData )
3542   {
3543     return;
3544   }
3545
3546   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
3547                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
3548                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3549
3550   // TODO: At the moment the underline runs are only for pre-edit.
3551   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
3552
3553   // Remove the previous InputMethodContext pre-edit.
3554   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
3555   {
3556     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
3557                                   mImpl->mEventData->mPreEditLength,
3558                                   DONT_UPDATE_INPUT_STYLE );
3559
3560     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
3561     mImpl->mEventData->mPreEditLength = 0u;
3562   }
3563   else
3564   {
3565     // Remove the previous Selection.
3566     removedSelected = RemoveSelectedText();
3567
3568   }
3569
3570   Vector<Character> utf32Characters;
3571   Length characterCount = 0u;
3572
3573   if( !text.empty() )
3574   {
3575     //  Convert text into UTF-32
3576     utf32Characters.Resize( text.size() );
3577
3578     // This is a bit horrible but std::string returns a (signed) char*
3579     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
3580
3581     // Transform a text array encoded in utf8 into an array encoded in utf32.
3582     // It returns the actual number of characters.
3583     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
3584     utf32Characters.Resize( characterCount );
3585
3586     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
3587     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
3588   }
3589
3590   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
3591   {
3592     // The placeholder text is no longer needed
3593     if( mImpl->IsShowingPlaceholderText() )
3594     {
3595       ResetText();
3596     }
3597
3598     mImpl->ChangeState( EventData::EDITING );
3599
3600     // Handle the InputMethodContext (predicitive text) state changes
3601     if( COMMIT == type )
3602     {
3603       // InputMethodContext is no longer handling key-events
3604       mImpl->ClearPreEditFlag();
3605     }
3606     else // PRE_EDIT
3607     {
3608       if( !mImpl->mEventData->mPreEditFlag )
3609       {
3610         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
3611
3612         // Record the start of the pre-edit text
3613         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
3614       }
3615
3616       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
3617       mImpl->mEventData->mPreEditFlag = true;
3618
3619       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3620     }
3621
3622     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
3623
3624     // Restrict new text to fit within Maximum characters setting.
3625     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
3626     maxLengthReached = ( characterCount > maxSizeOfNewText );
3627
3628     // The cursor position.
3629     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3630
3631     // Update the text's style.
3632
3633     // Updates the text style runs by adding characters.
3634     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
3635
3636     // Get the character index from the cursor index.
3637     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
3638
3639     // Retrieve the text's style for the given index.
3640     InputStyle style;
3641     mImpl->RetrieveDefaultInputStyle( style );
3642     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3643
3644     // Whether to add a new text color run.
3645     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor ) && !mImpl->mEventData->mInputStyle.isDefaultColor;
3646
3647     // Whether to add a new font run.
3648     const bool addFontNameRun = ( style.familyName != mImpl->mEventData->mInputStyle.familyName ) && mImpl->mEventData->mInputStyle.isFamilyDefined;
3649     const bool addFontWeightRun = ( style.weight != mImpl->mEventData->mInputStyle.weight ) && mImpl->mEventData->mInputStyle.isWeightDefined;
3650     const bool addFontWidthRun = ( style.width != mImpl->mEventData->mInputStyle.width ) && mImpl->mEventData->mInputStyle.isWidthDefined;
3651     const bool addFontSlantRun = ( style.slant != mImpl->mEventData->mInputStyle.slant ) && mImpl->mEventData->mInputStyle.isSlantDefined;
3652     const bool addFontSizeRun = ( style.size != mImpl->mEventData->mInputStyle.size ) && mImpl->mEventData->mInputStyle.isSizeDefined ;
3653
3654     // Add style runs.
3655     if( addColorRun )
3656     {
3657       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3658       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3659
3660       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3661       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3662       colorRun.characterRun.characterIndex = cursorIndex;
3663       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3664     }
3665
3666     if( addFontNameRun   ||
3667         addFontWeightRun ||
3668         addFontWidthRun  ||
3669         addFontSlantRun  ||
3670         addFontSizeRun )
3671     {
3672       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3673       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3674
3675       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3676
3677       if( addFontNameRun )
3678       {
3679         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3680         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3681         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3682         fontDescriptionRun.familyDefined = true;
3683
3684         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3685       }
3686
3687       if( addFontWeightRun )
3688       {
3689         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3690         fontDescriptionRun.weightDefined = true;
3691       }
3692
3693       if( addFontWidthRun )
3694       {
3695         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3696         fontDescriptionRun.widthDefined = true;
3697       }
3698
3699       if( addFontSlantRun )
3700       {
3701         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3702         fontDescriptionRun.slantDefined = true;
3703       }
3704
3705       if( addFontSizeRun )
3706       {
3707         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3708         fontDescriptionRun.sizeDefined = true;
3709       }
3710
3711       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3712       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3713     }
3714
3715     // Insert at current cursor position.
3716     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3717
3718     if( cursorIndex < numberOfCharactersInModel )
3719     {
3720       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3721     }
3722     else
3723     {
3724       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3725     }
3726
3727     // Mark the first paragraph to be updated.
3728     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3729     {
3730       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3731       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3732       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3733       mImpl->mTextUpdateInfo.mClearAll = true;
3734     }
3735     else
3736     {
3737       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3738       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3739     }
3740
3741     // Update the cursor index.
3742     cursorIndex += maxSizeOfNewText;
3743
3744     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 );
3745   }
3746
3747   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3748       mImpl->IsPlaceholderAvailable() )
3749   {
3750     // Show place-holder if empty after removing the pre-edit text
3751     ShowPlaceholderText();
3752     mImpl->mEventData->mUpdateCursorPosition = true;
3753     mImpl->ClearPreEditFlag();
3754   }
3755   else if( removedPrevious ||
3756            removedSelected ||
3757            ( 0 != utf32Characters.Count() ) )
3758   {
3759     // Queue an inserted event
3760     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3761
3762     mImpl->mEventData->mUpdateCursorPosition = true;
3763     if( removedSelected )
3764     {
3765       mImpl->mEventData->mScrollAfterDelete = true;
3766     }
3767     else
3768     {
3769       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3770     }
3771   }
3772
3773   if( maxLengthReached )
3774   {
3775     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3776
3777     mImpl->ResetInputMethodContext();
3778
3779     if( NULL != mImpl->mEditableControlInterface )
3780     {
3781       // Do this last since it provides callbacks into application code
3782       mImpl->mEditableControlInterface->MaxLengthReached();
3783     }
3784   }
3785 }
3786
3787 void Controller::PasteText( const std::string& stringToPaste )
3788 {
3789   InsertText( stringToPaste, Text::Controller::COMMIT );
3790   mImpl->ChangeState( EventData::EDITING );
3791   mImpl->RequestRelayout();
3792
3793   if( NULL != mImpl->mEditableControlInterface )
3794   {
3795     // Do this last since it provides callbacks into application code
3796     mImpl->mEditableControlInterface->TextChanged();
3797   }
3798 }
3799
3800 bool Controller::RemoveText( int cursorOffset,
3801                              int numberOfCharacters,
3802                              UpdateInputStyleType type )
3803 {
3804   bool removed = false;
3805
3806   if( NULL == mImpl->mEventData )
3807   {
3808     return removed;
3809   }
3810
3811   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3812                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3813
3814   if( !mImpl->IsShowingPlaceholderText() )
3815   {
3816     // Delete at current cursor position
3817     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3818     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3819
3820     CharacterIndex cursorIndex = 0;
3821
3822     // Validate the cursor position & number of characters
3823     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3824     {
3825       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3826     }
3827
3828     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3829     {
3830       numberOfCharacters = currentText.Count() - cursorIndex;
3831     }
3832
3833     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.
3834         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
3835     {
3836       // Mark the paragraphs to be updated.
3837       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3838       {
3839         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3840         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3841         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3842         mImpl->mTextUpdateInfo.mClearAll = true;
3843       }
3844       else
3845       {
3846         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3847         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3848       }
3849
3850       // Update the input style and remove the text's style before removing the text.
3851
3852       if( UPDATE_INPUT_STYLE == type )
3853       {
3854         // Keep a copy of the current input style.
3855         InputStyle currentInputStyle;
3856         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3857
3858         // Set first the default input style.
3859         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3860
3861         // Update the input style.
3862         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3863
3864         // Compare if the input style has changed.
3865         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3866
3867         if( hasInputStyleChanged )
3868         {
3869           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3870           // Queue the input style changed signal.
3871           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3872         }
3873       }
3874
3875       // If the number of current text and the number of characters to be deleted are same,
3876       // it means all texts should be removed and all Preedit variables should be initialized.
3877       if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) )
3878       {
3879         mImpl->ClearPreEditFlag();
3880         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
3881       }
3882
3883       // Updates the text style runs by removing characters. Runs with no characters are removed.
3884       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3885
3886       // Remove the characters.
3887       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3888       Vector<Character>::Iterator last  = first + numberOfCharacters;
3889
3890       currentText.Erase( first, last );
3891
3892       // Cursor position retreat
3893       oldCursorIndex = cursorIndex;
3894
3895       mImpl->mEventData->mScrollAfterDelete = true;
3896
3897       if( EventData::INACTIVE == mImpl->mEventData->mState )
3898       {
3899         mImpl->ChangeState( EventData::EDITING );
3900       }
3901
3902       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3903       removed = true;
3904     }
3905   }
3906
3907   return removed;
3908 }
3909
3910 bool Controller::RemoveSelectedText()
3911 {
3912   bool textRemoved( false );
3913
3914   if( EventData::SELECTING == mImpl->mEventData->mState )
3915   {
3916     std::string removedString;
3917     mImpl->RetrieveSelection( removedString, true );
3918
3919     if( !removedString.empty() )
3920     {
3921       textRemoved = true;
3922       mImpl->ChangeState( EventData::EDITING );
3923     }
3924   }
3925
3926   return textRemoved;
3927 }
3928
3929 std::string Controller::GetSelectedText()
3930 {
3931   std::string text;
3932   if( EventData::SELECTING == mImpl->mEventData->mState )
3933   {
3934     mImpl->RetrieveSelection( text, false );
3935   }
3936   return text;
3937 }
3938
3939 // private : Relayout.
3940
3941 bool Controller::DoRelayout( const Size& size,
3942                              OperationsMask operationsRequired,
3943                              Size& layoutSize )
3944 {
3945   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3946   bool viewUpdated( false );
3947
3948   // Calculate the operations to be done.
3949   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3950
3951   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3952   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3953
3954   // Get the current layout size.
3955   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3956
3957   if( NO_OPERATION != ( LAYOUT & operations ) )
3958   {
3959     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3960
3961     // Some vectors with data needed to layout and reorder may be void
3962     // after the first time the text has been laid out.
3963     // Fill the vectors again.
3964
3965     // Calculate the number of glyphs to layout.
3966     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3967     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3968     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3969     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3970
3971     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3972     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3973
3974     // Make sure the index is not out of bound
3975     if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
3976          requestedNumberOfCharacters > charactersToGlyph.Count() ||
3977          ( lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
3978     {
3979       std::string currentText;
3980       GetText( currentText );
3981
3982       DALI_LOG_ERROR( "Controller::DoRelayout: Attempting to access invalid buffer\n" );
3983       DALI_LOG_ERROR( "Current text is: %s\n", currentText.c_str() );
3984       DALI_LOG_ERROR( "startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
3985
3986       return false;
3987     }
3988
3989     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3990     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3991
3992     if( 0u == totalNumberOfGlyphs )
3993     {
3994       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3995       {
3996         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3997       }
3998
3999       // Nothing else to do if there is no glyphs.
4000       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
4001       return true;
4002     }
4003
4004     // Set the layout parameters.
4005     Layout::Parameters layoutParameters( size,
4006                                          mImpl->mModel);
4007
4008     // Resize the vector of positions to have the same size than the vector of glyphs.
4009     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
4010     glyphPositions.Resize( totalNumberOfGlyphs );
4011
4012     // Whether the last character is a new paragraph character.
4013     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
4014     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
4015     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
4016
4017     // The initial glyph and the number of glyphs to layout.
4018     layoutParameters.startGlyphIndex = startGlyphIndex;
4019     layoutParameters.numberOfGlyphs = numberOfGlyphs;
4020     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
4021     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
4022
4023     // Update the ellipsis
4024     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
4025
4026     if( NULL != mImpl->mEventData )
4027     {
4028       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
4029       {
4030         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
4031       }
4032       else if( EventData::INACTIVE != mImpl->mEventData->mState )
4033       {
4034         // Disable ellipsis when editing
4035         elideTextEnabled = false;
4036       }
4037
4038       // Reset the scroll position in inactive state
4039       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
4040       {
4041         ResetScrollPosition();
4042       }
4043     }
4044
4045     // Update the visual model.
4046     bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
4047     Size newLayoutSize;
4048     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
4049                                                    newLayoutSize,
4050                                                    elideTextEnabled,
4051                                                    isAutoScrollEnabled );
4052     mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
4053
4054     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
4055
4056     if( viewUpdated )
4057     {
4058       layoutSize = newLayoutSize;
4059
4060       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
4061       {
4062         mImpl->mIsTextDirectionRTL = false;
4063       }
4064
4065       if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && !mImpl->mModel->mVisualModel->mLines.Empty() )
4066       {
4067         mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
4068       }
4069
4070       // Sets the layout size.
4071       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
4072       {
4073         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
4074       }
4075     } // view updated
4076   }
4077
4078   if( NO_OPERATION != ( ALIGN & operations ) )
4079   {
4080     // The laid-out lines.
4081     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
4082
4083     CharacterIndex alignStartIndex = startIndex;
4084     Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
4085
4086     // the whole text needs to be full aligned.
4087     // If you do not do a full aligned, only the last line of the multiline input is aligned.
4088     if(  mImpl->mEventData && mImpl->mEventData->mUpdateAlignment )
4089     {
4090       alignStartIndex = 0u;
4091       alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
4092       mImpl->mEventData->mUpdateAlignment = false;
4093     }
4094
4095     // Need to align with the control's size as the text may contain lines
4096     // starting either with left to right text or right to left.
4097     mImpl->mLayoutEngine.Align( size,
4098                                 alignStartIndex,
4099                                 alignRequestedNumberOfCharacters,
4100                                 mImpl->mModel->mHorizontalAlignment,
4101                                 lines,
4102                                 mImpl->mModel->mAlignmentOffset,
4103                                 mImpl->mLayoutDirection,
4104                                 mImpl->mModel->mMatchSystemLanguageDirection );
4105
4106     viewUpdated = true;
4107   }
4108 #if defined(DEBUG_ENABLED)
4109   std::string currentText;
4110   GetText( currentText );
4111   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false",  currentText.c_str() );
4112 #endif
4113   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
4114   return viewUpdated;
4115 }
4116
4117 void Controller::CalculateVerticalOffset( const Size& controlSize )
4118 {
4119   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
4120
4121   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
4122   {
4123     // Get the line height of the default font.
4124     layoutSize.height = mImpl->GetDefaultFontLineHeight();
4125   }
4126
4127   switch( mImpl->mModel->mVerticalAlignment )
4128   {
4129     case VerticalAlignment::TOP:
4130     {
4131       mImpl->mModel->mScrollPosition.y = 0.f;
4132       break;
4133     }
4134     case VerticalAlignment::CENTER:
4135     {
4136       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
4137       break;
4138     }
4139     case VerticalAlignment::BOTTOM:
4140     {
4141       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
4142       break;
4143     }
4144   }
4145 }
4146
4147 // private : Events.
4148
4149 void Controller::ProcessModifyEvents()
4150 {
4151   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
4152
4153   if( 0u == events.Count() )
4154   {
4155     // Nothing to do.
4156     return;
4157   }
4158
4159   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
4160          endIt = events.End();
4161        it != endIt;
4162        ++it )
4163   {
4164     const ModifyEvent& event = *it;
4165
4166     if( ModifyEvent::TEXT_REPLACED == event.type )
4167     {
4168       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
4169       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
4170
4171       TextReplacedEvent();
4172     }
4173     else if( ModifyEvent::TEXT_INSERTED == event.type )
4174     {
4175       TextInsertedEvent();
4176     }
4177     else if( ModifyEvent::TEXT_DELETED == event.type )
4178     {
4179       // Placeholder-text cannot be deleted
4180       if( !mImpl->IsShowingPlaceholderText() )
4181       {
4182         TextDeletedEvent();
4183       }
4184     }
4185   }
4186
4187   if( NULL != mImpl->mEventData )
4188   {
4189     // When the text is being modified, delay cursor blinking
4190     mImpl->mEventData->mDecorator->DelayCursorBlink();
4191
4192     // Update selection position after modifying the text
4193     mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
4194     mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
4195   }
4196
4197   // DISCARD temporary text
4198   events.Clear();
4199 }
4200
4201 void Controller::TextReplacedEvent()
4202 {
4203   // The natural size needs to be re-calculated.
4204   mImpl->mRecalculateNaturalSize = true;
4205
4206   // The text direction needs to be updated.
4207   mImpl->mUpdateTextDirection = true;
4208
4209   // Apply modifications to the model
4210   mImpl->mOperationsPending = ALL_OPERATIONS;
4211 }
4212
4213 void Controller::TextInsertedEvent()
4214 {
4215   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
4216
4217   if( NULL == mImpl->mEventData )
4218   {
4219     return;
4220   }
4221
4222   mImpl->mEventData->mCheckScrollAmount = true;
4223
4224   // The natural size needs to be re-calculated.
4225   mImpl->mRecalculateNaturalSize = true;
4226
4227   // The text direction needs to be updated.
4228   mImpl->mUpdateTextDirection = true;
4229
4230   // Apply modifications to the model; TODO - Optimize this
4231   mImpl->mOperationsPending = ALL_OPERATIONS;
4232 }
4233
4234 void Controller::TextDeletedEvent()
4235 {
4236   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
4237
4238   if( NULL == mImpl->mEventData )
4239   {
4240     return;
4241   }
4242
4243   if (!IsEditable()) return;
4244
4245   mImpl->mEventData->mCheckScrollAmount = true;
4246
4247   // The natural size needs to be re-calculated.
4248   mImpl->mRecalculateNaturalSize = true;
4249
4250   // The text direction needs to be updated.
4251   mImpl->mUpdateTextDirection = true;
4252
4253   // Apply modifications to the model; TODO - Optimize this
4254   mImpl->mOperationsPending = ALL_OPERATIONS;
4255 }
4256
4257 bool Controller::DeleteEvent( int keyCode )
4258 {
4259   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
4260
4261   bool removed = false;
4262
4263   if( NULL == mImpl->mEventData )
4264   {
4265     return removed;
4266   }
4267
4268   if (!IsEditable()) return false;
4269
4270   // InputMethodContext is no longer handling key-events
4271   mImpl->ClearPreEditFlag();
4272
4273   if( EventData::SELECTING == mImpl->mEventData->mState )
4274   {
4275     removed = RemoveSelectedText();
4276   }
4277   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
4278   {
4279     // Remove the character before the current cursor position
4280     removed = RemoveText( -1,
4281                           1,
4282                           UPDATE_INPUT_STYLE );
4283   }
4284   else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE )
4285   {
4286     // Remove the character after the current cursor position
4287     removed = RemoveText( 0,
4288                           1,
4289                           UPDATE_INPUT_STYLE );
4290   }
4291
4292   if( removed )
4293   {
4294     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
4295         !mImpl->IsPlaceholderAvailable() )
4296     {
4297       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
4298     }
4299     else
4300     {
4301       ShowPlaceholderText();
4302     }
4303     mImpl->mEventData->mUpdateCursorPosition = true;
4304     mImpl->mEventData->mScrollAfterDelete = true;
4305   }
4306
4307   return removed;
4308 }
4309
4310 // private : Helpers.
4311
4312 void Controller::ResetText()
4313 {
4314   // Reset buffers.
4315   mImpl->mModel->mLogicalModel->mText.Clear();
4316
4317   // Reset the embedded images buffer.
4318   mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
4319
4320   // We have cleared everything including the placeholder-text
4321   mImpl->PlaceholderCleared();
4322
4323   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
4324   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
4325   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
4326
4327   // Clear any previous text.
4328   mImpl->mTextUpdateInfo.mClearAll = true;
4329
4330   // The natural size needs to be re-calculated.
4331   mImpl->mRecalculateNaturalSize = true;
4332
4333   // The text direction needs to be updated.
4334   mImpl->mUpdateTextDirection = true;
4335
4336   // Apply modifications to the model
4337   mImpl->mOperationsPending = ALL_OPERATIONS;
4338 }
4339
4340 void Controller::ShowPlaceholderText()
4341 {
4342   if( mImpl->IsPlaceholderAvailable() )
4343   {
4344     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
4345
4346     if( NULL == mImpl->mEventData )
4347     {
4348       return;
4349     }
4350
4351     mImpl->mEventData->mIsShowingPlaceholderText = true;
4352
4353     // Disable handles when showing place-holder text
4354     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
4355     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
4356     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
4357
4358     const char* text( NULL );
4359     size_t size( 0 );
4360
4361     // TODO - Switch Placeholder text when changing state
4362     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
4363         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
4364     {
4365       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
4366       size = mImpl->mEventData->mPlaceholderTextActive.size();
4367     }
4368     else
4369     {
4370       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
4371       size = mImpl->mEventData->mPlaceholderTextInactive.size();
4372     }
4373
4374     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
4375     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
4376
4377     // Reset model for showing placeholder.
4378     mImpl->mModel->mLogicalModel->mText.Clear();
4379     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
4380
4381     // Convert text into UTF-32
4382     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
4383     utf32Characters.Resize( size );
4384
4385     // This is a bit horrible but std::string returns a (signed) char*
4386     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
4387
4388     // Transform a text array encoded in utf8 into an array encoded in utf32.
4389     // It returns the actual number of characters.
4390     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
4391     utf32Characters.Resize( characterCount );
4392
4393     // The characters to be added.
4394     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
4395
4396     // Reset the cursor position
4397     mImpl->mEventData->mPrimaryCursorPosition = 0;
4398
4399     // The natural size needs to be re-calculated.
4400     mImpl->mRecalculateNaturalSize = true;
4401
4402     // The text direction needs to be updated.
4403     mImpl->mUpdateTextDirection = true;
4404
4405     // Apply modifications to the model
4406     mImpl->mOperationsPending = ALL_OPERATIONS;
4407
4408     // Update the rest of the model during size negotiation
4409     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
4410   }
4411 }
4412
4413 void Controller::ClearFontData()
4414 {
4415   if( mImpl->mFontDefaults )
4416   {
4417     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
4418   }
4419
4420   // Set flags to update the model.
4421   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
4422   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
4423   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
4424
4425   mImpl->mTextUpdateInfo.mClearAll = true;
4426   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
4427   mImpl->mRecalculateNaturalSize = true;
4428
4429   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
4430                                                            VALIDATE_FONTS            |
4431                                                            SHAPE_TEXT                |
4432                                                            BIDI_INFO                 |
4433                                                            GET_GLYPH_METRICS         |
4434                                                            LAYOUT                    |
4435                                                            UPDATE_LAYOUT_SIZE        |
4436                                                            REORDER                   |
4437                                                            ALIGN );
4438 }
4439
4440 void Controller::ClearStyleData()
4441 {
4442   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
4443   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
4444 }
4445
4446 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
4447 {
4448   // Reset the cursor position
4449   if( NULL != mImpl->mEventData )
4450   {
4451     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
4452
4453     // Update the cursor if it's in editing mode.
4454     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
4455     {
4456       mImpl->mEventData->mUpdateCursorPosition = true;
4457     }
4458   }
4459 }
4460
4461 void Controller::ResetScrollPosition()
4462 {
4463   if( NULL != mImpl->mEventData )
4464   {
4465     // Reset the scroll position.
4466     mImpl->mModel->mScrollPosition = Vector2::ZERO;
4467     mImpl->mEventData->mScrollAfterUpdatePosition = true;
4468   }
4469 }
4470
4471 void Controller::SetControlInterface( ControlInterface* controlInterface )
4472 {
4473   mImpl->mControlInterface = controlInterface;
4474 }
4475
4476 bool Controller::ShouldClearFocusOnEscape() const
4477 {
4478   return mImpl->mShouldClearFocusOnEscape;
4479 }
4480
4481 Actor Controller::CreateBackgroundActor()
4482 {
4483   return mImpl->CreateBackgroundActor();
4484 }
4485
4486 // private : Private contructors & copy operator.
4487
4488 Controller::Controller()
4489 : mImpl( NULL )
4490 {
4491   mImpl = new Controller::Impl( nullptr, nullptr, nullptr );
4492 }
4493
4494 Controller::Controller( ControlInterface* controlInterface )
4495 {
4496   mImpl = new Controller::Impl( controlInterface, NULL, NULL );
4497 }
4498
4499 Controller::Controller( ControlInterface* controlInterface,
4500                         EditableControlInterface* editableControlInterface,
4501                         SelectableControlInterface* selectableControlInterface )
4502 {
4503   mImpl = new Controller::Impl( controlInterface,
4504                                 editableControlInterface,
4505                                 selectableControlInterface );
4506 }
4507
4508 // The copy constructor and operator are left unimplemented.
4509
4510 // protected : Destructor.
4511
4512 Controller::~Controller()
4513 {
4514   delete mImpl;
4515 }
4516
4517 } // namespace Text
4518
4519 } // namespace Toolkit
4520
4521 } // namespace Dali