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