Outline effect has been fixed to be not front cropped.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <memory.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
27 #include <dali/devel-api/text-abstraction/font-client.h>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
31 #include <dali-toolkit/internal/text/bidirectional-support.h>
32 #include <dali-toolkit/internal/text/character-set-conversion.h>
33 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
34 #include <dali-toolkit/internal/text/markup-processor.h>
35 #include <dali-toolkit/internal/text/multi-language-support.h>
36 #include <dali-toolkit/internal/text/text-controller-impl.h>
37 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
38 #include <dali-toolkit/internal/text/text-font-style.h>
39
40 namespace
41 {
42
43 #if defined(DEBUG_ENABLED)
44   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
45 #endif
46
47 const float MAX_FLOAT = std::numeric_limits<float>::max();
48
49 const std::string EMPTY_STRING("");
50
51 const char * const PLACEHOLDER_TEXT = "text";
52 const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
53 const char * const PLACEHOLDER_COLOR = "color";
54 const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily";
55 const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
56 const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
57 const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
58 const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
59
60 float ConvertToEven( float value )
61 {
62   int intValue(static_cast<int>( value ));
63   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
64 }
65
66 } // namespace
67
68 namespace Dali
69 {
70
71 namespace Toolkit
72 {
73
74 namespace Text
75 {
76
77 /**
78  * @brief Adds a new font description run for the selected text.
79  *
80  * The new font parameters are added after the call to this method.
81  *
82  * @param[in] eventData The event data pointer.
83  * @param[in] logicalModel The logical model where to add the new font description run.
84  * @param[out] startOfSelectedText Index to the first selected character.
85  * @param[out] lengthOfSelectedText Number of selected characters.
86  */
87 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
88                                                  LogicalModelPtr logicalModel,
89                                                  CharacterIndex& startOfSelectedText,
90                                                  Length& lengthOfSelectedText )
91 {
92   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
93
94   // Get start and end position of selection
95   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
96   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
97
98   // Add the font run.
99   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
100   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
101
102   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
103
104   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
105   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
106
107   // Recalculate the selection highlight as the metrics may have changed.
108   eventData->mUpdateLeftSelectionPosition = true;
109   eventData->mUpdateRightSelectionPosition = true;
110   eventData->mUpdateHighlightBox = true;
111
112   return fontDescriptionRun;
113 }
114
115 // public : Constructor.
116
117 ControllerPtr Controller::New()
118 {
119   return ControllerPtr( new Controller() );
120 }
121
122 ControllerPtr Controller::New( ControlInterface* controlInterface )
123 {
124   return ControllerPtr( new Controller( controlInterface ) );
125 }
126
127 ControllerPtr Controller::New( ControlInterface* controlInterface,
128                                EditableControlInterface* editableControlInterface )
129 {
130   return ControllerPtr( new Controller( controlInterface,
131                                         editableControlInterface ) );
132 }
133
134 // public : Configure the text controller.
135
136 void Controller::EnableTextInput( DecoratorPtr decorator )
137 {
138   if( !decorator )
139   {
140     delete mImpl->mEventData;
141     mImpl->mEventData = NULL;
142
143     // Nothing else to do.
144     return;
145   }
146
147   if( NULL == mImpl->mEventData )
148   {
149     mImpl->mEventData = new EventData( decorator );
150   }
151 }
152
153 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
154 {
155   // Metrics for bitmap & vector based glyphs are different
156   mImpl->mMetrics->SetGlyphType( glyphType );
157
158   // Clear the font-specific data
159   ClearFontData();
160
161   mImpl->RequestRelayout();
162 }
163
164 void Controller::SetMarkupProcessorEnabled( bool enable )
165 {
166   mImpl->mMarkupProcessorEnabled = enable;
167 }
168
169 bool Controller::IsMarkupProcessorEnabled() const
170 {
171   return mImpl->mMarkupProcessorEnabled;
172 }
173
174 void Controller::SetAutoScrollEnabled( bool enable )
175 {
176   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 );
177
178   if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
179   {
180     if( enable )
181     {
182       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
183       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
184                                                                LAYOUT                    |
185                                                                ALIGN                     |
186                                                                UPDATE_LAYOUT_SIZE        |
187                                                                UPDATE_DIRECTION          |
188                                                                REORDER );
189
190     }
191     else
192     {
193       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
194       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
195                                                                LAYOUT                    |
196                                                                ALIGN                     |
197                                                                UPDATE_LAYOUT_SIZE        |
198                                                                REORDER );
199     }
200
201     mImpl->mIsAutoScrollEnabled = enable;
202     mImpl->RequestRelayout();
203   }
204   else
205   {
206     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
207     mImpl->mIsAutoScrollEnabled = false;
208   }
209 }
210
211 bool Controller::IsAutoScrollEnabled() const
212 {
213   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
214
215   return mImpl->mIsAutoScrollEnabled;
216 }
217
218 CharacterDirection Controller::GetAutoScrollDirection() const
219 {
220   return mImpl->mAutoScrollDirectionRTL;
221 }
222
223 float Controller::GetAutoScrollLineAlignment() const
224 {
225   float offset = 0.f;
226
227   if( mImpl->mModel->mVisualModel &&
228       ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
229   {
230     offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
231   }
232
233   return offset;
234 }
235
236 void Controller::SetHorizontalScrollEnabled( bool enable )
237 {
238   if( ( NULL != mImpl->mEventData ) &&
239       mImpl->mEventData->mDecorator )
240   {
241     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
242   }
243 }
244 bool Controller::IsHorizontalScrollEnabled() const
245 {
246   if( ( NULL != mImpl->mEventData ) &&
247       mImpl->mEventData->mDecorator )
248   {
249     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
250   }
251
252   return false;
253 }
254
255 void Controller::SetVerticalScrollEnabled( bool enable )
256 {
257   if( ( NULL != mImpl->mEventData ) &&
258       mImpl->mEventData->mDecorator )
259   {
260     if( mImpl->mEventData->mDecorator )
261     {
262       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
263     }
264   }
265 }
266
267 bool Controller::IsVerticalScrollEnabled() const
268 {
269   if( ( NULL != mImpl->mEventData ) &&
270       mImpl->mEventData->mDecorator )
271   {
272     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
273   }
274
275   return false;
276 }
277
278 void Controller::SetSmoothHandlePanEnabled( bool enable )
279 {
280   if( ( NULL != mImpl->mEventData ) &&
281       mImpl->mEventData->mDecorator )
282   {
283     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
284   }
285 }
286
287 bool Controller::IsSmoothHandlePanEnabled() const
288 {
289   if( ( NULL != mImpl->mEventData ) &&
290       mImpl->mEventData->mDecorator )
291   {
292     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
293   }
294
295   return false;
296 }
297
298 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
299 {
300   mImpl->mMaximumNumberOfCharacters = maxCharacters;
301 }
302
303 int Controller::GetMaximumNumberOfCharacters()
304 {
305   return mImpl->mMaximumNumberOfCharacters;
306 }
307
308 void Controller::SetEnableCursorBlink( bool enable )
309 {
310   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
311
312   if( NULL != mImpl->mEventData )
313   {
314     mImpl->mEventData->mCursorBlinkEnabled = enable;
315
316     if( !enable &&
317         mImpl->mEventData->mDecorator )
318     {
319       mImpl->mEventData->mDecorator->StopCursorBlink();
320     }
321   }
322 }
323
324 bool Controller::GetEnableCursorBlink() const
325 {
326   if( NULL != mImpl->mEventData )
327   {
328     return mImpl->mEventData->mCursorBlinkEnabled;
329   }
330
331   return false;
332 }
333
334 void Controller::SetMultiLineEnabled( bool enable )
335 {
336   const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
337
338   if( layout != mImpl->mLayoutEngine.GetLayout() )
339   {
340     // Set the layout type.
341     mImpl->mLayoutEngine.SetLayout( layout );
342
343     // Set the flags to redo the layout operations
344     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
345                                                                           UPDATE_LAYOUT_SIZE |
346                                                                           ALIGN              |
347                                                                           REORDER );
348
349     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
350
351     mImpl->RequestRelayout();
352   }
353 }
354
355 bool Controller::IsMultiLineEnabled() const
356 {
357   return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
358 }
359
360 void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
361 {
362   if( alignment != mImpl->mModel->mHorizontalAlignment )
363   {
364     // Set the alignment.
365     mImpl->mModel->mHorizontalAlignment = alignment;
366
367     // Set the flag to redo the alignment operation.
368     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
369
370     mImpl->RequestRelayout();
371   }
372 }
373
374 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
375 {
376   return mImpl->mModel->mHorizontalAlignment;
377 }
378
379 void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
380 {
381   if( alignment != mImpl->mModel->mVerticalAlignment )
382   {
383     // Set the alignment.
384     mImpl->mModel->mVerticalAlignment = alignment;
385
386     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
387
388     mImpl->RequestRelayout();
389   }
390 }
391
392 VerticalAlignment::Type Controller::GetVerticalAlignment() const
393 {
394   return mImpl->mModel->mVerticalAlignment;
395 }
396
397 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
398 {
399   if( lineWrapMode != mImpl->mModel->mLineWrapMode )
400   {
401     // Set the text wrap mode.
402     mImpl->mModel->mLineWrapMode = lineWrapMode;
403
404
405     // Update Text layout for applying wrap mode
406     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
407                                                              ALIGN                     |
408                                                              LAYOUT                    |
409                                                              UPDATE_LAYOUT_SIZE        |
410                                                              REORDER                   );
411     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
412     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
413     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
414
415     // Request relayout
416     mImpl->RequestRelayout();
417   }
418 }
419
420 Text::LineWrap::Mode Controller::GetLineWrapMode() const
421 {
422   return mImpl->mModel->mLineWrapMode;
423 }
424
425 void Controller::SetTextElideEnabled( bool enabled )
426 {
427   mImpl->mModel->mElideEnabled = enabled;
428 }
429
430 bool Controller::IsTextElideEnabled() const
431 {
432   return mImpl->mModel->mElideEnabled;
433 }
434
435 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
436 {
437   mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
438   mImpl->mEventData->mPlaceholderEllipsisFlag = true;
439
440   // Update placeholder if there is no text
441   if( mImpl->IsShowingPlaceholderText() ||
442       ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
443   {
444     ShowPlaceholderText();
445   }
446 }
447
448 bool Controller::IsPlaceholderTextElideEnabled() const
449 {
450   return mImpl->mEventData->mIsPlaceholderElideEnabled;
451 }
452
453 void Controller::SetSelectionEnabled( bool enabled )
454 {
455   mImpl->mEventData->mSelectionEnabled = enabled;
456 }
457
458 bool Controller::IsSelectionEnabled() const
459 {
460   return mImpl->mEventData->mSelectionEnabled;
461 }
462
463 // public : Update
464
465 void Controller::SetText( const std::string& text )
466 {
467   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
468
469   // Reset keyboard as text changed
470   mImpl->ResetImfManager();
471
472   // Remove the previously set text and style.
473   ResetText();
474
475   // Remove the style.
476   ClearStyleData();
477
478   CharacterIndex lastCursorIndex = 0u;
479
480   if( NULL != mImpl->mEventData )
481   {
482     // If popup shown then hide it by switching to Editing state
483     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
484         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
485         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
486         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
487     {
488       mImpl->ChangeState( EventData::EDITING );
489     }
490   }
491
492   if( !text.empty() )
493   {
494     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
495
496     MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
497                                          mImpl->mModel->mLogicalModel->mFontDescriptionRuns );
498
499     Length textSize = 0u;
500     const uint8_t* utf8 = NULL;
501     if( mImpl->mMarkupProcessorEnabled )
502     {
503       ProcessMarkupString( text, markupProcessData );
504       textSize = markupProcessData.markupProcessedText.size();
505
506       // This is a bit horrible but std::string returns a (signed) char*
507       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
508     }
509     else
510     {
511       textSize = text.size();
512
513       // This is a bit horrible but std::string returns a (signed) char*
514       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
515     }
516
517     //  Convert text into UTF-32
518     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
519     utf32Characters.Resize( textSize );
520
521     // Transform a text array encoded in utf8 into an array encoded in utf32.
522     // It returns the actual number of characters.
523     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
524     utf32Characters.Resize( characterCount );
525
526     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
527     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
528
529     // The characters to be added.
530     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
531
532     // To reset the cursor position
533     lastCursorIndex = characterCount;
534
535     // Update the rest of the model during size negotiation
536     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
537
538     // The natural size needs to be re-calculated.
539     mImpl->mRecalculateNaturalSize = true;
540
541     // Apply modifications to the model
542     mImpl->mOperationsPending = ALL_OPERATIONS;
543   }
544   else
545   {
546     ShowPlaceholderText();
547   }
548
549   // Resets the cursor position.
550   ResetCursorPosition( lastCursorIndex );
551
552   // Scrolls the text to make the cursor visible.
553   ResetScrollPosition();
554
555   mImpl->RequestRelayout();
556
557   if( NULL != mImpl->mEventData )
558   {
559     // Cancel previously queued events
560     mImpl->mEventData->mEventQueue.clear();
561   }
562
563   // Do this last since it provides callbacks into application code.
564   if( NULL != mImpl->mEditableControlInterface )
565   {
566     mImpl->mEditableControlInterface->TextChanged();
567   }
568 }
569
570 void Controller::GetText( std::string& text ) const
571 {
572   if( !mImpl->IsShowingPlaceholderText() )
573   {
574     // Retrieves the text string.
575     mImpl->GetText( 0u, text );
576   }
577   else
578   {
579     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
580   }
581 }
582
583 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
584 {
585   if( NULL != mImpl->mEventData )
586   {
587     if( PLACEHOLDER_TYPE_INACTIVE == type )
588     {
589       mImpl->mEventData->mPlaceholderTextInactive = text;
590     }
591     else
592     {
593       mImpl->mEventData->mPlaceholderTextActive = text;
594     }
595
596     // Update placeholder if there is no text
597     if( mImpl->IsShowingPlaceholderText() ||
598         ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
599     {
600       ShowPlaceholderText();
601     }
602   }
603 }
604
605 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
606 {
607   if( NULL != mImpl->mEventData )
608   {
609     if( PLACEHOLDER_TYPE_INACTIVE == type )
610     {
611       text = mImpl->mEventData->mPlaceholderTextInactive;
612     }
613     else
614     {
615       text = mImpl->mEventData->mPlaceholderTextActive;
616     }
617   }
618 }
619
620 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
621 {
622   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
623
624   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
625   {
626     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
627     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
628
629     ClearFontData();
630
631     mImpl->RequestRelayout();
632   }
633 }
634
635 // public : Default style & Input style
636
637 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
638 {
639   if( NULL == mImpl->mFontDefaults )
640   {
641     mImpl->mFontDefaults = new FontDefaults();
642   }
643
644   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
645   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
646   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
647
648   // Clear the font-specific data
649   ClearFontData();
650
651   mImpl->RequestRelayout();
652 }
653
654 const std::string& Controller::GetDefaultFontFamily() const
655 {
656   if( NULL != mImpl->mFontDefaults )
657   {
658     return mImpl->mFontDefaults->mFontDescription.family;
659   }
660
661   return EMPTY_STRING;
662 }
663
664 void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
665 {
666   if( NULL != mImpl->mEventData )
667   {
668     if( NULL == mImpl->mEventData->mPlaceholderFont )
669     {
670       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
671     }
672
673     mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
674     DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
675     mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
676
677     mImpl->RequestRelayout();
678   }
679 }
680
681 const std::string& Controller::GetPlaceholderFontFamily() const
682 {
683   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
684   {
685     return mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
686   }
687
688   return EMPTY_STRING;
689 }
690
691 void Controller::SetDefaultFontWeight( FontWeight weight )
692 {
693   if( NULL == mImpl->mFontDefaults )
694   {
695     mImpl->mFontDefaults = new FontDefaults();
696   }
697
698   mImpl->mFontDefaults->mFontDescription.weight = weight;
699   mImpl->mFontDefaults->weightDefined = true;
700
701   // Clear the font-specific data
702   ClearFontData();
703
704   mImpl->RequestRelayout();
705 }
706
707 bool Controller::IsDefaultFontWeightDefined() const
708 {
709   if( NULL != mImpl->mFontDefaults )
710   {
711     return mImpl->mFontDefaults->weightDefined;
712   }
713
714   return false;
715 }
716
717 FontWeight Controller::GetDefaultFontWeight() const
718 {
719   if( NULL != mImpl->mFontDefaults )
720   {
721     return mImpl->mFontDefaults->mFontDescription.weight;
722   }
723
724   return TextAbstraction::FontWeight::NORMAL;
725 }
726
727 void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
728 {
729   if( NULL != mImpl->mEventData )
730   {
731     if( NULL == mImpl->mEventData->mPlaceholderFont )
732     {
733       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
734     }
735
736     mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
737     mImpl->mEventData->mPlaceholderFont->weightDefined = true;
738
739     mImpl->RequestRelayout();
740   }
741 }
742
743 bool Controller::IsPlaceholderTextFontWeightDefined() const
744 {
745   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
746   {
747     return mImpl->mEventData->mPlaceholderFont->weightDefined;
748   }
749   return false;
750 }
751
752 FontWeight Controller::GetPlaceholderTextFontWeight() const
753 {
754   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
755   {
756     return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
757   }
758
759   return TextAbstraction::FontWeight::NORMAL;
760 }
761
762 void Controller::SetDefaultFontWidth( FontWidth width )
763 {
764   if( NULL == mImpl->mFontDefaults )
765   {
766     mImpl->mFontDefaults = new FontDefaults();
767   }
768
769   mImpl->mFontDefaults->mFontDescription.width = width;
770   mImpl->mFontDefaults->widthDefined = true;
771
772   // Clear the font-specific data
773   ClearFontData();
774
775   mImpl->RequestRelayout();
776 }
777
778 bool Controller::IsDefaultFontWidthDefined() const
779 {
780   if( NULL != mImpl->mFontDefaults )
781   {
782     return mImpl->mFontDefaults->widthDefined;
783   }
784
785   return false;
786 }
787
788 FontWidth Controller::GetDefaultFontWidth() const
789 {
790   if( NULL != mImpl->mFontDefaults )
791   {
792     return mImpl->mFontDefaults->mFontDescription.width;
793   }
794
795   return TextAbstraction::FontWidth::NORMAL;
796 }
797
798 void Controller::SetPlaceholderTextFontWidth( FontWidth width )
799 {
800   if( NULL != mImpl->mEventData )
801   {
802     if( NULL == mImpl->mEventData->mPlaceholderFont )
803     {
804       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
805     }
806
807     mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
808     mImpl->mEventData->mPlaceholderFont->widthDefined = true;
809
810     mImpl->RequestRelayout();
811   }
812 }
813
814 bool Controller::IsPlaceholderTextFontWidthDefined() const
815 {
816   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
817   {
818     return mImpl->mEventData->mPlaceholderFont->widthDefined;
819   }
820   return false;
821 }
822
823 FontWidth Controller::GetPlaceholderTextFontWidth() const
824 {
825   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
826   {
827     return mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
828   }
829
830   return TextAbstraction::FontWidth::NORMAL;
831 }
832
833 void Controller::SetDefaultFontSlant( FontSlant slant )
834 {
835   if( NULL == mImpl->mFontDefaults )
836   {
837     mImpl->mFontDefaults = new FontDefaults();
838   }
839
840   mImpl->mFontDefaults->mFontDescription.slant = slant;
841   mImpl->mFontDefaults->slantDefined = true;
842
843   // Clear the font-specific data
844   ClearFontData();
845
846   mImpl->RequestRelayout();
847 }
848
849 bool Controller::IsDefaultFontSlantDefined() const
850 {
851   if( NULL != mImpl->mFontDefaults )
852   {
853     return mImpl->mFontDefaults->slantDefined;
854   }
855   return false;
856 }
857
858 FontSlant Controller::GetDefaultFontSlant() const
859 {
860   if( NULL != mImpl->mFontDefaults )
861   {
862     return mImpl->mFontDefaults->mFontDescription.slant;
863   }
864
865   return TextAbstraction::FontSlant::NORMAL;
866 }
867
868 void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
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.slant = slant;
878     mImpl->mEventData->mPlaceholderFont->slantDefined = true;
879
880     mImpl->RequestRelayout();
881   }
882 }
883
884 bool Controller::IsPlaceholderTextFontSlantDefined() const
885 {
886   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
887   {
888     return mImpl->mEventData->mPlaceholderFont->slantDefined;
889   }
890   return false;
891 }
892
893 FontSlant Controller::GetPlaceholderTextFontSlant() const
894 {
895   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
896   {
897     return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
898   }
899
900   return TextAbstraction::FontSlant::NORMAL;
901 }
902
903 void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
904 {
905   if( NULL == mImpl->mFontDefaults )
906   {
907     mImpl->mFontDefaults = new FontDefaults();
908   }
909
910   switch( type )
911   {
912     case POINT_SIZE:
913     {
914       mImpl->mFontDefaults->mDefaultPointSize = fontSize;
915       mImpl->mFontDefaults->sizeDefined = true;
916       break;
917     }
918     case PIXEL_SIZE:
919     {
920       // Point size = Pixel size * 72.f / DPI
921       unsigned int horizontalDpi = 0u;
922       unsigned int verticalDpi = 0u;
923       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
924       fontClient.GetDpi( horizontalDpi, verticalDpi );
925
926       mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
927       mImpl->mFontDefaults->sizeDefined = true;
928       break;
929     }
930   }
931
932   // Clear the font-specific data
933   ClearFontData();
934
935   mImpl->RequestRelayout();
936 }
937
938 float Controller::GetDefaultFontSize( FontSizeType type ) const
939 {
940   float value = 0.0f;
941   if( NULL != mImpl->mFontDefaults )
942   {
943     switch( type )
944     {
945       case POINT_SIZE:
946       {
947         value = mImpl->mFontDefaults->mDefaultPointSize;
948         break;
949       }
950       case PIXEL_SIZE:
951       {
952         // Pixel size = Point size * DPI / 72.f
953         unsigned int horizontalDpi = 0u;
954         unsigned int verticalDpi = 0u;
955         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
956         fontClient.GetDpi( horizontalDpi, verticalDpi );
957
958         value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
959         break;
960       }
961     }
962     return value;
963   }
964
965   return value;
966 }
967
968 void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
969 {
970   if( NULL != mImpl->mEventData )
971   {
972     if( NULL == mImpl->mEventData->mPlaceholderFont )
973     {
974       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
975     }
976
977     switch( type )
978     {
979       case POINT_SIZE:
980       {
981         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
982         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
983         mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
984         break;
985       }
986       case PIXEL_SIZE:
987       {
988         // Point size = Pixel size * 72.f / DPI
989         unsigned int horizontalDpi = 0u;
990         unsigned int verticalDpi = 0u;
991         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
992         fontClient.GetDpi( horizontalDpi, verticalDpi );
993
994         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
995         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
996         mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
997         break;
998       }
999     }
1000
1001     mImpl->RequestRelayout();
1002   }
1003 }
1004
1005 float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
1006 {
1007   float value = 0.0f;
1008   if( NULL != mImpl->mEventData )
1009   {
1010     switch( type )
1011     {
1012       case POINT_SIZE:
1013       {
1014         if( NULL != mImpl->mEventData->mPlaceholderFont )
1015         {
1016           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
1017         }
1018         else
1019         {
1020           // If the placeholder text font size is not set, then return the default font size.
1021           value = GetDefaultFontSize( POINT_SIZE );
1022         }
1023         break;
1024       }
1025       case PIXEL_SIZE:
1026       {
1027         if( NULL != mImpl->mEventData->mPlaceholderFont )
1028         {
1029           // Pixel size = Point size * DPI / 72.f
1030           unsigned int horizontalDpi = 0u;
1031           unsigned int verticalDpi = 0u;
1032           TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1033           fontClient.GetDpi( horizontalDpi, verticalDpi );
1034
1035           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1036         }
1037         else
1038         {
1039           // If the placeholder text font size is not set, then return the default font size.
1040           value = GetDefaultFontSize( PIXEL_SIZE );
1041         }
1042         break;
1043       }
1044     }
1045     return value;
1046   }
1047
1048   return value;
1049 }
1050
1051 void Controller::SetDefaultColor( const Vector4& color )
1052 {
1053   mImpl->mTextColor = color;
1054
1055   if( !mImpl->IsShowingPlaceholderText() )
1056   {
1057     mImpl->mModel->mVisualModel->SetTextColor( color );
1058
1059     mImpl->RequestRelayout();
1060   }
1061 }
1062
1063 const Vector4& Controller::GetDefaultColor() const
1064 {
1065   return mImpl->mTextColor;
1066 }
1067
1068 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
1069 {
1070   if( NULL != mImpl->mEventData )
1071   {
1072     mImpl->mEventData->mPlaceholderTextColor = textColor;
1073   }
1074
1075   if( mImpl->IsShowingPlaceholderText() )
1076   {
1077     mImpl->mModel->mVisualModel->SetTextColor( textColor );
1078     mImpl->RequestRelayout();
1079   }
1080 }
1081
1082 const Vector4& Controller::GetPlaceholderTextColor() const
1083 {
1084   if( NULL != mImpl->mEventData )
1085   {
1086     return mImpl->mEventData->mPlaceholderTextColor;
1087   }
1088
1089   return Color::BLACK;
1090 }
1091
1092 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1093 {
1094   mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
1095
1096   mImpl->RequestRelayout();
1097 }
1098
1099 const Vector2& Controller::GetShadowOffset() const
1100 {
1101   return mImpl->mModel->mVisualModel->GetShadowOffset();
1102 }
1103
1104 void Controller::SetShadowColor( const Vector4& shadowColor )
1105 {
1106   mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
1107
1108   mImpl->RequestRelayout();
1109 }
1110
1111 const Vector4& Controller::GetShadowColor() const
1112 {
1113   return mImpl->mModel->mVisualModel->GetShadowColor();
1114 }
1115
1116 void Controller::SetShadowBlurRadius( const float& shadowBlurRadius )
1117 {
1118   if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 )
1119   {
1120     mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius );
1121
1122     mImpl->RequestRelayout();
1123   }
1124 }
1125
1126 const float& Controller::GetShadowBlurRadius() const
1127 {
1128   return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1129 }
1130
1131 void Controller::SetUnderlineColor( const Vector4& color )
1132 {
1133   mImpl->mModel->mVisualModel->SetUnderlineColor( color );
1134
1135   mImpl->RequestRelayout();
1136 }
1137
1138 const Vector4& Controller::GetUnderlineColor() const
1139 {
1140   return mImpl->mModel->mVisualModel->GetUnderlineColor();
1141 }
1142
1143 void Controller::SetUnderlineEnabled( bool enabled )
1144 {
1145   mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
1146
1147   mImpl->RequestRelayout();
1148 }
1149
1150 bool Controller::IsUnderlineEnabled() const
1151 {
1152   return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1153 }
1154
1155 void Controller::SetUnderlineHeight( float height )
1156 {
1157   mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
1158
1159   mImpl->RequestRelayout();
1160 }
1161
1162 float Controller::GetUnderlineHeight() const
1163 {
1164   return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1165 }
1166
1167 void Controller::SetOutlineColor( const Vector4& color )
1168 {
1169   mImpl->mModel->mVisualModel->SetOutlineColor( color );
1170
1171   mImpl->RequestRelayout();
1172 }
1173
1174 const Vector4& Controller::GetOutlineColor() const
1175 {
1176   return mImpl->mModel->mVisualModel->GetOutlineColor();
1177 }
1178
1179 void Controller::SetOutlineWidth( float width )
1180 {
1181   mImpl->mModel->mVisualModel->SetOutlineWidth( width );
1182
1183   mImpl->RequestRelayout();
1184 }
1185
1186 float Controller::GetOutlineWidth() const
1187 {
1188   return mImpl->mModel->mVisualModel->GetOutlineWidth();
1189 }
1190
1191 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
1192 {
1193   if( NULL == mImpl->mEmbossDefaults )
1194   {
1195     mImpl->mEmbossDefaults = new EmbossDefaults();
1196   }
1197
1198   mImpl->mEmbossDefaults->properties = embossProperties;
1199 }
1200
1201 const std::string& Controller::GetDefaultEmbossProperties() const
1202 {
1203   if( NULL != mImpl->mEmbossDefaults )
1204   {
1205     return mImpl->mEmbossDefaults->properties;
1206   }
1207
1208   return EMPTY_STRING;
1209 }
1210
1211 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
1212 {
1213   if( NULL == mImpl->mOutlineDefaults )
1214   {
1215     mImpl->mOutlineDefaults = new OutlineDefaults();
1216   }
1217
1218   mImpl->mOutlineDefaults->properties = outlineProperties;
1219 }
1220
1221 const std::string& Controller::GetDefaultOutlineProperties() const
1222 {
1223   if( NULL != mImpl->mOutlineDefaults )
1224   {
1225     return mImpl->mOutlineDefaults->properties;
1226   }
1227
1228   return EMPTY_STRING;
1229 }
1230
1231 void Controller::SetDefaultLineSpacing( float lineSpacing )
1232 {
1233   //TODO finish implementation
1234   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
1235 }
1236
1237 float Controller::GetDefaultLineSpacing() const
1238 {
1239   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1240 }
1241
1242 void Controller::SetInputColor( const Vector4& color )
1243 {
1244   if( NULL != mImpl->mEventData )
1245   {
1246     mImpl->mEventData->mInputStyle.textColor = color;
1247     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1248
1249     if( EventData::SELECTING == mImpl->mEventData->mState )
1250     {
1251       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1252
1253       // Get start and end position of selection
1254       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1255       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1256
1257       // Add the color run.
1258       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1259       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1260
1261       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1262       colorRun.color = color;
1263       colorRun.characterRun.characterIndex = startOfSelectedText;
1264       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1265
1266       // Request to relayout.
1267       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1268       mImpl->RequestRelayout();
1269
1270       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1271       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1272       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1273     }
1274   }
1275 }
1276
1277 const Vector4& Controller::GetInputColor() const
1278 {
1279   if( NULL != mImpl->mEventData )
1280   {
1281     return mImpl->mEventData->mInputStyle.textColor;
1282   }
1283
1284   // Return the default text's color if there is no EventData.
1285   return mImpl->mTextColor;
1286
1287 }
1288
1289 void Controller::SetInputFontFamily( const std::string& fontFamily )
1290 {
1291   if( NULL != mImpl->mEventData )
1292   {
1293     mImpl->mEventData->mInputStyle.familyName = fontFamily;
1294     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
1295
1296     if( EventData::SELECTING == mImpl->mEventData->mState )
1297     {
1298       CharacterIndex startOfSelectedText = 0u;
1299       Length lengthOfSelectedText = 0u;
1300       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1301                                                                             mImpl->mModel->mLogicalModel,
1302                                                                             startOfSelectedText,
1303                                                                             lengthOfSelectedText );
1304
1305       fontDescriptionRun.familyLength = fontFamily.size();
1306       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
1307       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
1308       fontDescriptionRun.familyDefined = true;
1309
1310       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
1311
1312       // Request to relayout.
1313       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1314                                                                VALIDATE_FONTS            |
1315                                                                SHAPE_TEXT                |
1316                                                                GET_GLYPH_METRICS         |
1317                                                                LAYOUT                    |
1318                                                                UPDATE_LAYOUT_SIZE        |
1319                                                                REORDER                   |
1320                                                                ALIGN );
1321       mImpl->mRecalculateNaturalSize = true;
1322       mImpl->RequestRelayout();
1323
1324       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1325       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1326       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1327
1328       // As the font changes, recalculate the handle positions is needed.
1329       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1330       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1331       mImpl->mEventData->mUpdateHighlightBox = true;
1332       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1333     }
1334   }
1335 }
1336
1337 const std::string& Controller::GetInputFontFamily() const
1338 {
1339   if( NULL != mImpl->mEventData )
1340   {
1341     return mImpl->mEventData->mInputStyle.familyName;
1342   }
1343
1344   // Return the default font's family if there is no EventData.
1345   return GetDefaultFontFamily();
1346 }
1347
1348 void Controller::SetInputFontWeight( FontWeight weight )
1349 {
1350   if( NULL != mImpl->mEventData )
1351   {
1352     mImpl->mEventData->mInputStyle.weight = weight;
1353     mImpl->mEventData->mInputStyle.isWeightDefined = true;
1354
1355     if( EventData::SELECTING == mImpl->mEventData->mState )
1356     {
1357       CharacterIndex startOfSelectedText = 0u;
1358       Length lengthOfSelectedText = 0u;
1359       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1360                                                                             mImpl->mModel->mLogicalModel,
1361                                                                             startOfSelectedText,
1362                                                                             lengthOfSelectedText );
1363
1364       fontDescriptionRun.weight = weight;
1365       fontDescriptionRun.weightDefined = true;
1366
1367       // Request to relayout.
1368       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1369                                                                VALIDATE_FONTS            |
1370                                                                SHAPE_TEXT                |
1371                                                                GET_GLYPH_METRICS         |
1372                                                                LAYOUT                    |
1373                                                                UPDATE_LAYOUT_SIZE        |
1374                                                                REORDER                   |
1375                                                                ALIGN );
1376       mImpl->mRecalculateNaturalSize = true;
1377       mImpl->RequestRelayout();
1378
1379       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1380       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1381       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1382
1383       // As the font might change, recalculate the handle positions is needed.
1384       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1385       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1386       mImpl->mEventData->mUpdateHighlightBox = true;
1387       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1388     }
1389   }
1390 }
1391
1392 bool Controller::IsInputFontWeightDefined() const
1393 {
1394   bool defined = false;
1395
1396   if( NULL != mImpl->mEventData )
1397   {
1398     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1399   }
1400
1401   return defined;
1402 }
1403
1404 FontWeight Controller::GetInputFontWeight() const
1405 {
1406   if( NULL != mImpl->mEventData )
1407   {
1408     return mImpl->mEventData->mInputStyle.weight;
1409   }
1410
1411   return GetDefaultFontWeight();
1412 }
1413
1414 void Controller::SetInputFontWidth( FontWidth width )
1415 {
1416   if( NULL != mImpl->mEventData )
1417   {
1418     mImpl->mEventData->mInputStyle.width = width;
1419     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1420
1421     if( EventData::SELECTING == mImpl->mEventData->mState )
1422     {
1423       CharacterIndex startOfSelectedText = 0u;
1424       Length lengthOfSelectedText = 0u;
1425       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1426                                                                             mImpl->mModel->mLogicalModel,
1427                                                                             startOfSelectedText,
1428                                                                             lengthOfSelectedText );
1429
1430       fontDescriptionRun.width = width;
1431       fontDescriptionRun.widthDefined = true;
1432
1433       // Request to relayout.
1434       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1435                                                                VALIDATE_FONTS            |
1436                                                                SHAPE_TEXT                |
1437                                                                GET_GLYPH_METRICS         |
1438                                                                LAYOUT                    |
1439                                                                UPDATE_LAYOUT_SIZE        |
1440                                                                REORDER                   |
1441                                                                ALIGN );
1442       mImpl->mRecalculateNaturalSize = true;
1443       mImpl->RequestRelayout();
1444
1445       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1446       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1447       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1448
1449       // As the font might change, recalculate the handle positions is needed.
1450       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1451       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1452       mImpl->mEventData->mUpdateHighlightBox = true;
1453       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1454     }
1455   }
1456 }
1457
1458 bool Controller::IsInputFontWidthDefined() const
1459 {
1460   bool defined = false;
1461
1462   if( NULL != mImpl->mEventData )
1463   {
1464     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1465   }
1466
1467   return defined;
1468 }
1469
1470 FontWidth Controller::GetInputFontWidth() const
1471 {
1472   if( NULL != mImpl->mEventData )
1473   {
1474     return mImpl->mEventData->mInputStyle.width;
1475   }
1476
1477   return GetDefaultFontWidth();
1478 }
1479
1480 void Controller::SetInputFontSlant( FontSlant slant )
1481 {
1482   if( NULL != mImpl->mEventData )
1483   {
1484     mImpl->mEventData->mInputStyle.slant = slant;
1485     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1486
1487     if( EventData::SELECTING == mImpl->mEventData->mState )
1488     {
1489       CharacterIndex startOfSelectedText = 0u;
1490       Length lengthOfSelectedText = 0u;
1491       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1492                                                                             mImpl->mModel->mLogicalModel,
1493                                                                             startOfSelectedText,
1494                                                                             lengthOfSelectedText );
1495
1496       fontDescriptionRun.slant = slant;
1497       fontDescriptionRun.slantDefined = true;
1498
1499       // Request to relayout.
1500       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1501                                                                VALIDATE_FONTS            |
1502                                                                SHAPE_TEXT                |
1503                                                                GET_GLYPH_METRICS         |
1504                                                                LAYOUT                    |
1505                                                                UPDATE_LAYOUT_SIZE        |
1506                                                                REORDER                   |
1507                                                                ALIGN );
1508       mImpl->mRecalculateNaturalSize = true;
1509       mImpl->RequestRelayout();
1510
1511       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1512       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1513       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1514
1515       // As the font might change, recalculate the handle positions is needed.
1516       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1517       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1518       mImpl->mEventData->mUpdateHighlightBox = true;
1519       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1520     }
1521   }
1522 }
1523
1524 bool Controller::IsInputFontSlantDefined() const
1525 {
1526   bool defined = false;
1527
1528   if( NULL != mImpl->mEventData )
1529   {
1530     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1531   }
1532
1533   return defined;
1534 }
1535
1536 FontSlant Controller::GetInputFontSlant() const
1537 {
1538   if( NULL != mImpl->mEventData )
1539   {
1540     return mImpl->mEventData->mInputStyle.slant;
1541   }
1542
1543   return GetDefaultFontSlant();
1544 }
1545
1546 void Controller::SetInputFontPointSize( float size )
1547 {
1548   if( NULL != mImpl->mEventData )
1549   {
1550     mImpl->mEventData->mInputStyle.size = size;
1551     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1552
1553     if( EventData::SELECTING == mImpl->mEventData->mState )
1554     {
1555       CharacterIndex startOfSelectedText = 0u;
1556       Length lengthOfSelectedText = 0u;
1557       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1558                                                                             mImpl->mModel->mLogicalModel,
1559                                                                             startOfSelectedText,
1560                                                                             lengthOfSelectedText );
1561
1562       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1563       fontDescriptionRun.sizeDefined = true;
1564
1565       // Request to relayout.
1566       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1567                                                                VALIDATE_FONTS            |
1568                                                                SHAPE_TEXT                |
1569                                                                GET_GLYPH_METRICS         |
1570                                                                LAYOUT                    |
1571                                                                UPDATE_LAYOUT_SIZE        |
1572                                                                REORDER                   |
1573                                                                ALIGN );
1574       mImpl->mRecalculateNaturalSize = true;
1575       mImpl->RequestRelayout();
1576
1577       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1578       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1579       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1580
1581       // As the font might change, recalculate the handle positions is needed.
1582       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1583       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1584       mImpl->mEventData->mUpdateHighlightBox = true;
1585       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1586     }
1587   }
1588 }
1589
1590 float Controller::GetInputFontPointSize() const
1591 {
1592   if( NULL != mImpl->mEventData )
1593   {
1594     return mImpl->mEventData->mInputStyle.size;
1595   }
1596
1597   // Return the default font's point size if there is no EventData.
1598   return GetDefaultFontSize( Text::Controller::POINT_SIZE );
1599 }
1600
1601 void Controller::SetInputLineSpacing( float lineSpacing )
1602 {
1603   if( NULL != mImpl->mEventData )
1604   {
1605     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1606     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1607   }
1608 }
1609
1610 float Controller::GetInputLineSpacing() const
1611 {
1612   if( NULL != mImpl->mEventData )
1613   {
1614     return mImpl->mEventData->mInputStyle.lineSpacing;
1615   }
1616
1617   return 0.f;
1618 }
1619
1620 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1621 {
1622   if( NULL != mImpl->mEventData )
1623   {
1624     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1625   }
1626 }
1627
1628 const std::string& Controller::GetInputShadowProperties() const
1629 {
1630   if( NULL != mImpl->mEventData )
1631   {
1632     return mImpl->mEventData->mInputStyle.shadowProperties;
1633   }
1634
1635   return EMPTY_STRING;
1636 }
1637
1638 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1639 {
1640   if( NULL != mImpl->mEventData )
1641   {
1642     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1643   }
1644 }
1645
1646 const std::string& Controller::GetInputUnderlineProperties() const
1647 {
1648   if( NULL != mImpl->mEventData )
1649   {
1650     return mImpl->mEventData->mInputStyle.underlineProperties;
1651   }
1652
1653   return EMPTY_STRING;
1654 }
1655
1656 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1657 {
1658   if( NULL != mImpl->mEventData )
1659   {
1660     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1661   }
1662 }
1663
1664 const std::string& Controller::GetInputEmbossProperties() const
1665 {
1666   if( NULL != mImpl->mEventData )
1667   {
1668     return mImpl->mEventData->mInputStyle.embossProperties;
1669   }
1670
1671   return GetDefaultEmbossProperties();
1672 }
1673
1674 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1675 {
1676   if( NULL != mImpl->mEventData )
1677   {
1678     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1679   }
1680 }
1681
1682 const std::string& Controller::GetInputOutlineProperties() const
1683 {
1684   if( NULL != mImpl->mEventData )
1685   {
1686     return mImpl->mEventData->mInputStyle.outlineProperties;
1687   }
1688
1689   return GetDefaultOutlineProperties();
1690 }
1691
1692 void Controller::SetInputModePassword( bool passwordInput )
1693 {
1694   if( NULL != mImpl->mEventData )
1695   {
1696     mImpl->mEventData->mPasswordInput = passwordInput;
1697   }
1698 }
1699
1700 bool Controller::IsInputModePassword()
1701 {
1702   if( NULL != mImpl->mEventData )
1703   {
1704     return mImpl->mEventData->mPasswordInput;
1705   }
1706   return false;
1707 }
1708
1709 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1710 {
1711   if( NULL != mImpl->mEventData )
1712   {
1713     mImpl->mEventData->mDoubleTapAction = action;
1714   }
1715 }
1716
1717 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1718 {
1719   NoTextTap::Action action = NoTextTap::NO_ACTION;
1720
1721   if( NULL != mImpl->mEventData )
1722   {
1723     action = mImpl->mEventData->mDoubleTapAction;
1724   }
1725
1726   return action;
1727 }
1728
1729 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1730 {
1731   if( NULL != mImpl->mEventData )
1732   {
1733     mImpl->mEventData->mLongPressAction = action;
1734   }
1735 }
1736
1737 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1738 {
1739   NoTextTap::Action action = NoTextTap::NO_ACTION;
1740
1741   if( NULL != mImpl->mEventData )
1742   {
1743     action = mImpl->mEventData->mLongPressAction;
1744   }
1745
1746   return action;
1747 }
1748
1749 bool Controller::IsUnderlineSetByString()
1750 {
1751   return mImpl->mUnderlineSetByString;
1752 }
1753
1754 void Controller::UnderlineSetByString( bool setByString )
1755 {
1756   mImpl->mUnderlineSetByString = setByString;
1757 }
1758
1759 bool Controller::IsShadowSetByString()
1760 {
1761   return mImpl->mShadowSetByString;
1762 }
1763
1764 void Controller::ShadowSetByString( bool setByString )
1765 {
1766   mImpl->mShadowSetByString = setByString;
1767 }
1768
1769 bool Controller::IsOutlineSetByString()
1770 {
1771   return mImpl->mOutlineSetByString;
1772 }
1773
1774 void Controller::OutlineSetByString( bool setByString )
1775 {
1776   mImpl->mOutlineSetByString = setByString;
1777 }
1778
1779 bool Controller::IsFontStyleSetByString()
1780 {
1781   return mImpl->mFontStyleSetByString;
1782 }
1783
1784 void Controller::FontStyleSetByString( bool setByString )
1785 {
1786   mImpl->mFontStyleSetByString = setByString;
1787 }
1788
1789 // public : Queries & retrieves.
1790
1791 Layout::Engine& Controller::GetLayoutEngine()
1792 {
1793   return mImpl->mLayoutEngine;
1794 }
1795
1796 View& Controller::GetView()
1797 {
1798   return mImpl->mView;
1799 }
1800
1801 Vector3 Controller::GetNaturalSize()
1802 {
1803   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1804   Vector3 naturalSize;
1805
1806   // Make sure the model is up-to-date before layouting
1807   ProcessModifyEvents();
1808
1809   if( mImpl->mRecalculateNaturalSize )
1810   {
1811     // Operations that can be done only once until the text changes.
1812     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1813                                                                            GET_SCRIPTS       |
1814                                                                            VALIDATE_FONTS    |
1815                                                                            GET_LINE_BREAKS   |
1816                                                                            GET_WORD_BREAKS   |
1817                                                                            BIDI_INFO         |
1818                                                                            SHAPE_TEXT        |
1819                                                                            GET_GLYPH_METRICS );
1820
1821     // Set the update info to relayout the whole text.
1822     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1823     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1824
1825     // Make sure the model is up-to-date before layouting
1826     mImpl->UpdateModel( onlyOnceOperations );
1827
1828     // Layout the text for the new width.
1829     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
1830
1831     // Store the actual control's size to restore later.
1832     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1833
1834     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1835                 static_cast<OperationsMask>( onlyOnceOperations |
1836                                              LAYOUT | REORDER ),
1837                 naturalSize.GetVectorXY() );
1838
1839     // Do not do again the only once operations.
1840     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1841
1842     // Do the size related operations again.
1843     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1844                                                                         ALIGN  |
1845                                                                         REORDER );
1846     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1847
1848     // Stores the natural size to avoid recalculate it again
1849     // unless the text/style changes.
1850     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1851
1852     mImpl->mRecalculateNaturalSize = false;
1853
1854     // Clear the update info. This info will be set the next time the text is updated.
1855     mImpl->mTextUpdateInfo.Clear();
1856
1857     // Restore the actual control's size.
1858     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1859
1860     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1861   }
1862   else
1863   {
1864     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1865
1866     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1867   }
1868
1869   naturalSize.x = ConvertToEven( naturalSize.x );
1870   naturalSize.y = ConvertToEven( naturalSize.y );
1871
1872   return naturalSize;
1873 }
1874
1875 float Controller::GetHeightForWidth( float width )
1876 {
1877   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1878   // Make sure the model is up-to-date before layouting
1879   ProcessModifyEvents();
1880
1881   Size layoutSize;
1882   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
1883                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1884                                                          mImpl->mTextUpdateInfo.mClearAll            )
1885   {
1886     // Operations that can be done only once until the text changes.
1887     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1888                                                                            GET_SCRIPTS       |
1889                                                                            VALIDATE_FONTS    |
1890                                                                            GET_LINE_BREAKS   |
1891                                                                            GET_WORD_BREAKS   |
1892                                                                            BIDI_INFO         |
1893                                                                            SHAPE_TEXT        |
1894                                                                            GET_GLYPH_METRICS );
1895
1896     // Set the update info to relayout the whole text.
1897     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1898     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1899
1900     // Make sure the model is up-to-date before layouting
1901     mImpl->UpdateModel( onlyOnceOperations );
1902
1903
1904     // Layout the text for the new width.
1905     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1906
1907     // Store the actual control's width.
1908     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1909
1910     DoRelayout( Size( width, MAX_FLOAT ),
1911                 static_cast<OperationsMask>( onlyOnceOperations |
1912                                              LAYOUT ),
1913                 layoutSize );
1914
1915     // Do not do again the only once operations.
1916     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1917
1918     // Do the size related operations again.
1919     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1920                                                                         ALIGN  |
1921                                                                         REORDER );
1922
1923     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1924
1925     // Clear the update info. This info will be set the next time the text is updated.
1926     mImpl->mTextUpdateInfo.Clear();
1927
1928     // Restore the actual control's width.
1929     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1930
1931     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1932   }
1933   else
1934   {
1935     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1936     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1937   }
1938
1939   return layoutSize.height;
1940 }
1941
1942 int Controller::GetLineCount( float width )
1943 {
1944   GetHeightForWidth( width );
1945   int numberofLines = mImpl->mModel->GetNumberOfLines();
1946   return numberofLines;
1947 }
1948
1949 const ModelInterface* const Controller::GetTextModel() const
1950 {
1951   return mImpl->mModel.Get();
1952 }
1953
1954 float Controller::GetScrollAmountByUserInput()
1955 {
1956   float scrollAmount = 0.0f;
1957
1958   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1959   {
1960     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1961     mImpl->mEventData->mCheckScrollAmount = false;
1962   }
1963   return scrollAmount;
1964 }
1965
1966 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1967 {
1968   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1969   bool isScrolled;
1970
1971   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1972   layoutHeight = layout.height;
1973   scrollPosition = mImpl->mModel->mScrollPosition.y;
1974   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1975   return isScrolled;
1976 }
1977
1978 void Controller::SetHiddenInputOption(const Property::Map& options )
1979 {
1980   if( NULL == mImpl->mHiddenInput )
1981   {
1982     mImpl->mHiddenInput = new HiddenText( this );
1983   }
1984   mImpl->mHiddenInput->SetProperties(options);
1985 }
1986
1987 void Controller::GetHiddenInputOption(Property::Map& options )
1988 {
1989   if( NULL != mImpl->mHiddenInput )
1990   {
1991     mImpl->mHiddenInput->GetProperties(options);
1992   }
1993 }
1994
1995 void Controller::SetPlaceholderProperty( const Property::Map& map )
1996 {
1997   const Property::Map::SizeType count = map.Count();
1998
1999   for( Property::Map::SizeType position = 0; position < count; ++position )
2000   {
2001     KeyValuePair keyValue = map.GetKeyValue( position );
2002     Property::Key& key = keyValue.first;
2003     Property::Value& value = keyValue.second;
2004
2005     if( key == Toolkit::Text::PlaceHolder::Property::TEXT  || key == PLACEHOLDER_TEXT )
2006     {
2007       std::string text = "";
2008       value.Get( text );
2009       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
2010     }
2011     else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
2012     {
2013       std::string text = "";
2014       value.Get( text );
2015       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
2016     }
2017     else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
2018     {
2019       Vector4 textColor;
2020       value.Get( textColor );
2021       if( GetPlaceholderTextColor() != textColor )
2022       {
2023         SetPlaceholderTextColor( textColor );
2024       }
2025     }
2026     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
2027     {
2028       std::string fontFamily = "";
2029       value.Get( fontFamily );
2030       SetPlaceholderFontFamily( fontFamily );
2031     }
2032     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
2033     {
2034       SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
2035     }
2036     else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
2037     {
2038       float pointSize;
2039       value.Get( pointSize );
2040       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
2041       {
2042         SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
2043       }
2044     }
2045     else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
2046     {
2047       float pixelSize;
2048       value.Get( pixelSize );
2049       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
2050       {
2051         SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
2052       }
2053     }
2054     else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
2055     {
2056       bool ellipsis;
2057       value.Get( ellipsis );
2058       SetPlaceholderTextElideEnabled( ellipsis );
2059     }
2060   }
2061 }
2062
2063 void Controller::GetPlaceholderProperty( Property::Map& map )
2064 {
2065   if( NULL != mImpl->mEventData )
2066   {
2067     if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
2068     {
2069       map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
2070     }
2071     if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
2072     {
2073       map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
2074     }
2075
2076     map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
2077     map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily();
2078
2079     Property::Value fontStyleMapGet;
2080     GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
2081     map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
2082
2083     // Choose font size : POINT_SIZE or PIXEL_SIZE
2084     if( !mImpl->mEventData->mIsPlaceholderPixelSize )
2085     {
2086       map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
2087     }
2088     else
2089     {
2090       map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
2091     }
2092
2093     if( mImpl->mEventData->mPlaceholderEllipsisFlag )
2094     {
2095       map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled();
2096     }
2097   }
2098 }
2099
2100 // public : Relayout.
2101
2102 Controller::UpdateTextType Controller::Relayout( const Size& size )
2103 {
2104   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2105
2106   UpdateTextType updateTextType = NONE_UPDATED;
2107
2108   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2109   {
2110     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2111     {
2112       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2113       updateTextType = MODEL_UPDATED;
2114     }
2115
2116     // Clear the update info. This info will be set the next time the text is updated.
2117     mImpl->mTextUpdateInfo.Clear();
2118
2119     // Not worth to relayout if width or height is equal to zero.
2120     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2121
2122     return updateTextType;
2123   }
2124
2125   // Whether a new size has been set.
2126   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2127
2128   if( newSize )
2129   {
2130     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2131
2132     // Layout operations that need to be done if the size changes.
2133     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2134                                                              LAYOUT                    |
2135                                                              ALIGN                     |
2136                                                              UPDATE_LAYOUT_SIZE        |
2137                                                              REORDER );
2138     // Set the update info to relayout the whole text.
2139     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2140     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2141
2142     // Store the size used to layout the text.
2143     mImpl->mModel->mVisualModel->mControlSize = size;
2144   }
2145
2146   // Whether there are modify events.
2147   if( 0u != mImpl->mModifyEvents.Count() )
2148   {
2149     // Style operations that need to be done if the text is modified.
2150     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2151                                                              COLOR );
2152   }
2153
2154   // Set the update info to elide the text.
2155   if( mImpl->mModel->mElideEnabled ||
2156       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2157   {
2158     // Update Text layout for applying elided
2159     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2160                                                              ALIGN                     |
2161                                                              LAYOUT                    |
2162                                                              UPDATE_LAYOUT_SIZE        |
2163                                                              REORDER );
2164     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2165     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2166   }
2167
2168   // Make sure the model is up-to-date before layouting.
2169   ProcessModifyEvents();
2170   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2171
2172   // Layout the text.
2173   Size layoutSize;
2174   updated = DoRelayout( size,
2175                         mImpl->mOperationsPending,
2176                         layoutSize ) || updated;
2177
2178   if( updated )
2179   {
2180     updateTextType = MODEL_UPDATED;
2181   }
2182
2183   // Do not re-do any operation until something changes.
2184   mImpl->mOperationsPending = NO_OPERATION;
2185   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2186
2187   // Whether the text control is editable
2188   const bool isEditable = NULL != mImpl->mEventData;
2189
2190   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2191   Vector2 offset;
2192   if( newSize && isEditable )
2193   {
2194     offset = mImpl->mModel->mScrollPosition;
2195   }
2196
2197   if( !isEditable || !IsMultiLineEnabled() )
2198   {
2199     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2200     CalculateVerticalOffset( size );
2201   }
2202
2203   if( isEditable )
2204   {
2205     if( newSize )
2206     {
2207       // If there is a new size, the scroll position needs to be clamped.
2208       mImpl->ClampHorizontalScroll( layoutSize );
2209
2210       // Update the decorator's positions is needed if there is a new size.
2211       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2212     }
2213
2214     // Move the cursor, grab handle etc.
2215     if( mImpl->ProcessInputEvents() )
2216     {
2217       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2218     }
2219   }
2220
2221   // Clear the update info. This info will be set the next time the text is updated.
2222   mImpl->mTextUpdateInfo.Clear();
2223   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2224
2225   return updateTextType;
2226 }
2227
2228 void Controller::RequestRelayout()
2229 {
2230   mImpl->RequestRelayout();
2231 }
2232
2233 // public : Input style change signals.
2234
2235 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2236 {
2237   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2238 }
2239
2240 void Controller::ProcessInputStyleChangedSignals()
2241 {
2242   if( NULL == mImpl->mEventData )
2243   {
2244     // Nothing to do.
2245     return;
2246   }
2247
2248   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2249          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2250        it != endIt;
2251        ++it )
2252   {
2253     const InputStyle::Mask mask = *it;
2254
2255     if( NULL != mImpl->mEditableControlInterface )
2256     {
2257       // Emit the input style changed signal.
2258       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2259     }
2260   }
2261
2262   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2263 }
2264
2265 // public : Text-input Event Queuing.
2266
2267 void Controller::KeyboardFocusGainEvent()
2268 {
2269   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2270
2271   if( NULL != mImpl->mEventData )
2272   {
2273     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2274         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2275     {
2276       mImpl->ChangeState( EventData::EDITING );
2277       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2278       mImpl->mEventData->mUpdateInputStyle = true;
2279     }
2280     mImpl->NotifyImfMultiLineStatus();
2281     if( mImpl->IsShowingPlaceholderText() )
2282     {
2283       // Show alternative placeholder-text when editing
2284       ShowPlaceholderText();
2285     }
2286
2287     mImpl->RequestRelayout();
2288   }
2289 }
2290
2291 void Controller::KeyboardFocusLostEvent()
2292 {
2293   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2294
2295   if( NULL != mImpl->mEventData )
2296   {
2297     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2298     {
2299       mImpl->ChangeState( EventData::INACTIVE );
2300
2301       if( !mImpl->IsShowingRealText() )
2302       {
2303         // Revert to regular placeholder-text when not editing
2304         ShowPlaceholderText();
2305       }
2306     }
2307   }
2308   mImpl->RequestRelayout();
2309 }
2310
2311 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2312 {
2313   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2314
2315   bool textChanged = false;
2316   bool relayoutNeeded = false;
2317
2318   if( ( NULL != mImpl->mEventData ) &&
2319       ( keyEvent.state == KeyEvent::Down ) )
2320   {
2321     int keyCode = keyEvent.keyCode;
2322     const std::string& keyString = keyEvent.keyPressed;
2323
2324     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2325
2326     // Pre-process to separate modifying events from non-modifying input events.
2327     if( isNullKey )
2328     {
2329       // In some platforms arrive key events with no key code.
2330       // Do nothing.
2331       return false;
2332     }
2333     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2334     {
2335       // Do nothing
2336       return false;
2337     }
2338     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2339              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2340              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2341              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2342     {
2343       // If don't have any text, do nothing.
2344       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2345       {
2346         return false;
2347       }
2348
2349       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2350       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2351       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2352       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2353
2354       // Logic to determine whether this text control will lose focus or not.
2355       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
2356           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
2357           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2358           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2359           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2360           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2361       {
2362         return false;
2363       }
2364
2365       mImpl->mEventData->mCheckScrollAmount = true;
2366       Event event( Event::CURSOR_KEY_EVENT );
2367       event.p1.mInt = keyCode;
2368       mImpl->mEventData->mEventQueue.push_back( event );
2369
2370       // Will request for relayout.
2371       relayoutNeeded = true;
2372     }
2373     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
2374     {
2375       textChanged = BackspaceKeyEvent();
2376
2377       // Will request for relayout.
2378       relayoutNeeded = true;
2379     }
2380     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2381              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2382              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2383     {
2384       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2385       mImpl->ChangeState( EventData::INACTIVE );
2386
2387       // Will request for relayout.
2388       relayoutNeeded = true;
2389
2390       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2391     }
2392     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2393     {
2394       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2395       // and a character is typed after the type of a upper case latin character.
2396
2397       // Do nothing.
2398       return false;
2399     }
2400     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2401     {
2402       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2403       // Do nothing.
2404       return false;
2405     }
2406     else
2407     {
2408       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2409
2410       // IMF manager is no longer handling key-events
2411       mImpl->ClearPreEditFlag();
2412
2413       InsertText( keyString, COMMIT );
2414       textChanged = true;
2415
2416       // Will request for relayout.
2417       relayoutNeeded = true;
2418     }
2419
2420     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2421          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2422          ( !isNullKey ) &&
2423          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2424          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2425          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2426     {
2427       // Should not change the state if the key is the shift send by the imf manager.
2428       // Otherwise, when the state is SELECTING the text controller can't send the right
2429       // surrounding info to the imf.
2430       mImpl->ChangeState( EventData::EDITING );
2431
2432       // Will request for relayout.
2433       relayoutNeeded = true;
2434     }
2435
2436     if( relayoutNeeded )
2437     {
2438       mImpl->RequestRelayout();
2439     }
2440   }
2441
2442   if( textChanged &&
2443       ( NULL != mImpl->mEditableControlInterface ) )
2444   {
2445     // Do this last since it provides callbacks into application code
2446     mImpl->mEditableControlInterface->TextChanged();
2447   }
2448
2449   return true;
2450 }
2451
2452 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2453 {
2454   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2455
2456   if( NULL != mImpl->mEventData )
2457   {
2458     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2459     EventData::State state( mImpl->mEventData->mState );
2460     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2461
2462     if( mImpl->IsClipboardVisible() )
2463     {
2464       if( EventData::INACTIVE == state || EventData::EDITING == state)
2465       {
2466         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2467       }
2468       relayoutNeeded = true;
2469     }
2470     else if( 1u == tapCount )
2471     {
2472       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2473       {
2474         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2475       }
2476
2477       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2478       {
2479         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2480         relayoutNeeded = true;
2481       }
2482       else
2483       {
2484         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2485         {
2486           // Hide placeholder text
2487           ResetText();
2488         }
2489
2490         if( EventData::INACTIVE == state )
2491         {
2492           mImpl->ChangeState( EventData::EDITING );
2493         }
2494         else if( !mImpl->IsClipboardEmpty() )
2495         {
2496           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2497         }
2498         relayoutNeeded = true;
2499       }
2500     }
2501     else if( 2u == tapCount )
2502     {
2503       if( mImpl->mEventData->mSelectionEnabled &&
2504           mImpl->IsShowingRealText() )
2505       {
2506         relayoutNeeded = true;
2507         mImpl->mEventData->mIsLeftHandleSelected = true;
2508         mImpl->mEventData->mIsRightHandleSelected = true;
2509       }
2510     }
2511
2512     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2513     if( relayoutNeeded )
2514     {
2515       Event event( Event::TAP_EVENT );
2516       event.p1.mUint = tapCount;
2517       event.p2.mFloat = x;
2518       event.p3.mFloat = y;
2519       mImpl->mEventData->mEventQueue.push_back( event );
2520
2521       mImpl->RequestRelayout();
2522     }
2523   }
2524
2525   // Reset keyboard as tap event has occurred.
2526   mImpl->ResetImfManager();
2527 }
2528
2529 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2530 {
2531   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2532
2533   if( NULL != mImpl->mEventData )
2534   {
2535     Event event( Event::PAN_EVENT );
2536     event.p1.mInt = state;
2537     event.p2.mFloat = displacement.x;
2538     event.p3.mFloat = displacement.y;
2539     mImpl->mEventData->mEventQueue.push_back( event );
2540
2541     mImpl->RequestRelayout();
2542   }
2543 }
2544
2545 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2546 {
2547   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2548
2549   if( ( state == Gesture::Started ) &&
2550       ( NULL != mImpl->mEventData ) )
2551   {
2552     // The 1st long-press on inactive text-field is treated as tap
2553     if( EventData::INACTIVE == mImpl->mEventData->mState )
2554     {
2555       mImpl->ChangeState( EventData::EDITING );
2556
2557       Event event( Event::TAP_EVENT );
2558       event.p1.mUint = 1;
2559       event.p2.mFloat = x;
2560       event.p3.mFloat = y;
2561       mImpl->mEventData->mEventQueue.push_back( event );
2562
2563       mImpl->RequestRelayout();
2564     }
2565     else if( !mImpl->IsShowingRealText() )
2566     {
2567       Event event( Event::LONG_PRESS_EVENT );
2568       event.p1.mInt = state;
2569       event.p2.mFloat = x;
2570       event.p3.mFloat = y;
2571       mImpl->mEventData->mEventQueue.push_back( event );
2572       mImpl->RequestRelayout();
2573     }
2574     else if( !mImpl->IsClipboardVisible() )
2575     {
2576       // Reset the imf manager to commit the pre-edit before selecting the text.
2577       mImpl->ResetImfManager();
2578
2579       Event event( Event::LONG_PRESS_EVENT );
2580       event.p1.mInt = state;
2581       event.p2.mFloat = x;
2582       event.p3.mFloat = y;
2583       mImpl->mEventData->mEventQueue.push_back( event );
2584       mImpl->RequestRelayout();
2585
2586       mImpl->mEventData->mIsLeftHandleSelected = true;
2587       mImpl->mEventData->mIsRightHandleSelected = true;
2588     }
2589   }
2590 }
2591
2592 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2593 {
2594   // Whether the text needs to be relaid-out.
2595   bool requestRelayout = false;
2596
2597   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2598   bool retrieveText = false;
2599   bool retrieveCursor = false;
2600
2601   switch( imfEvent.eventName )
2602   {
2603     case ImfManager::COMMIT:
2604     {
2605       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2606       requestRelayout = true;
2607       retrieveCursor = true;
2608       break;
2609     }
2610     case ImfManager::PREEDIT:
2611     {
2612       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2613       requestRelayout = true;
2614       retrieveCursor = true;
2615       break;
2616     }
2617     case ImfManager::DELETESURROUNDING:
2618     {
2619       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2620                                            imfEvent.numberOfChars,
2621                                            DONT_UPDATE_INPUT_STYLE );
2622
2623       if( textDeleted )
2624       {
2625         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2626             !mImpl->IsPlaceholderAvailable() )
2627         {
2628           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2629         }
2630         else
2631         {
2632           ShowPlaceholderText();
2633         }
2634         mImpl->mEventData->mUpdateCursorPosition = true;
2635         mImpl->mEventData->mScrollAfterDelete = true;
2636
2637         requestRelayout = true;
2638       }
2639       break;
2640     }
2641     case ImfManager::GETSURROUNDING:
2642     {
2643       retrieveText = true;
2644       retrieveCursor = true;
2645       break;
2646     }
2647     case ImfManager::PRIVATECOMMAND:
2648     {
2649       // PRIVATECOMMAND event is just for getting the private command message
2650       retrieveText = true;
2651       retrieveCursor = true;
2652       break;
2653     }
2654     case ImfManager::VOID:
2655     {
2656       // do nothing
2657       break;
2658     }
2659   } // end switch
2660
2661   if( requestRelayout )
2662   {
2663     mImpl->mOperationsPending = ALL_OPERATIONS;
2664     mImpl->RequestRelayout();
2665   }
2666
2667   std::string text;
2668   CharacterIndex cursorPosition = 0u;
2669   Length numberOfWhiteSpaces = 0u;
2670
2671   if( retrieveCursor )
2672   {
2673     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2674
2675     cursorPosition = mImpl->GetLogicalCursorPosition();
2676
2677     if( cursorPosition < numberOfWhiteSpaces )
2678     {
2679       cursorPosition = 0u;
2680     }
2681     else
2682     {
2683       cursorPosition -= numberOfWhiteSpaces;
2684     }
2685   }
2686
2687   if( retrieveText )
2688   {
2689     mImpl->GetText( numberOfWhiteSpaces, text );
2690   }
2691
2692   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2693
2694   if( requestRelayout &&
2695       ( NULL != mImpl->mEditableControlInterface ) )
2696   {
2697     // Do this last since it provides callbacks into application code
2698     mImpl->mEditableControlInterface->TextChanged();
2699   }
2700
2701   return callbackData;
2702 }
2703
2704 void Controller::PasteClipboardItemEvent()
2705 {
2706   // Retrieve the clipboard contents first
2707   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2708   std::string stringToPaste( notifier.GetContent() );
2709
2710   // Commit the current pre-edit text; the contents of the clipboard should be appended
2711   mImpl->ResetImfManager();
2712
2713   // Temporary disable hiding clipboard
2714   mImpl->SetClipboardHideEnable( false );
2715
2716   // Paste
2717   PasteText( stringToPaste );
2718
2719   mImpl->SetClipboardHideEnable( true );
2720 }
2721
2722 // protected : Inherit from Text::Decorator::ControllerInterface.
2723
2724 void Controller::GetTargetSize( Vector2& targetSize )
2725 {
2726   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2727 }
2728
2729 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2730 {
2731   if( NULL != mImpl->mEditableControlInterface )
2732   {
2733     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2734   }
2735 }
2736
2737 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2738 {
2739   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2740
2741   if( NULL != mImpl->mEventData )
2742   {
2743     switch( handleType )
2744     {
2745       case GRAB_HANDLE:
2746       {
2747         Event event( Event::GRAB_HANDLE_EVENT );
2748         event.p1.mUint  = state;
2749         event.p2.mFloat = x;
2750         event.p3.mFloat = y;
2751
2752         mImpl->mEventData->mEventQueue.push_back( event );
2753         break;
2754       }
2755       case LEFT_SELECTION_HANDLE:
2756       {
2757         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2758         event.p1.mUint  = state;
2759         event.p2.mFloat = x;
2760         event.p3.mFloat = y;
2761
2762         mImpl->mEventData->mEventQueue.push_back( event );
2763         break;
2764       }
2765       case RIGHT_SELECTION_HANDLE:
2766       {
2767         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2768         event.p1.mUint  = state;
2769         event.p2.mFloat = x;
2770         event.p3.mFloat = y;
2771
2772         mImpl->mEventData->mEventQueue.push_back( event );
2773         break;
2774       }
2775       case LEFT_SELECTION_HANDLE_MARKER:
2776       case RIGHT_SELECTION_HANDLE_MARKER:
2777       {
2778         // Markers do not move the handles.
2779         break;
2780       }
2781       case HANDLE_TYPE_COUNT:
2782       {
2783         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2784       }
2785     }
2786
2787     mImpl->RequestRelayout();
2788   }
2789 }
2790
2791 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2792
2793 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2794 {
2795   if( NULL == mImpl->mEventData )
2796   {
2797     return;
2798   }
2799
2800   switch( button )
2801   {
2802     case Toolkit::TextSelectionPopup::CUT:
2803     {
2804       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2805       mImpl->mOperationsPending = ALL_OPERATIONS;
2806
2807       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2808           !mImpl->IsPlaceholderAvailable() )
2809       {
2810         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2811       }
2812       else
2813       {
2814         ShowPlaceholderText();
2815       }
2816
2817       mImpl->mEventData->mUpdateCursorPosition = true;
2818       mImpl->mEventData->mScrollAfterDelete = true;
2819
2820       mImpl->RequestRelayout();
2821
2822       if( NULL != mImpl->mEditableControlInterface )
2823       {
2824         mImpl->mEditableControlInterface->TextChanged();
2825       }
2826       break;
2827     }
2828     case Toolkit::TextSelectionPopup::COPY:
2829     {
2830       mImpl->SendSelectionToClipboard( false ); // Text not modified
2831
2832       mImpl->mEventData->mUpdateCursorPosition = true;
2833
2834       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2835       break;
2836     }
2837     case Toolkit::TextSelectionPopup::PASTE:
2838     {
2839       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2840       break;
2841     }
2842     case Toolkit::TextSelectionPopup::SELECT:
2843     {
2844       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2845
2846       if( mImpl->mEventData->mSelectionEnabled )
2847       {
2848         // Creates a SELECT event.
2849         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2850       }
2851       break;
2852     }
2853     case Toolkit::TextSelectionPopup::SELECT_ALL:
2854     {
2855       // Creates a SELECT_ALL event
2856       SelectEvent( 0.f, 0.f, true );
2857       break;
2858     }
2859     case Toolkit::TextSelectionPopup::CLIPBOARD:
2860     {
2861       mImpl->ShowClipboard();
2862       break;
2863     }
2864     case Toolkit::TextSelectionPopup::NONE:
2865     {
2866       // Nothing to do.
2867       break;
2868     }
2869   }
2870 }
2871
2872 void Controller::DisplayTimeExpired()
2873 {
2874   mImpl->mEventData->mUpdateCursorPosition = true;
2875   // Apply modifications to the model
2876   mImpl->mOperationsPending = ALL_OPERATIONS;
2877
2878   mImpl->RequestRelayout();
2879 }
2880
2881 // private : Update.
2882
2883 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2884 {
2885   bool removedPrevious = false;
2886   bool removedSelected = false;
2887   bool maxLengthReached = false;
2888
2889   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2890
2891   if( NULL == mImpl->mEventData )
2892   {
2893     return;
2894   }
2895
2896   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2897                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2898                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2899
2900   // TODO: At the moment the underline runs are only for pre-edit.
2901   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2902
2903   // Remove the previous IMF pre-edit.
2904   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2905   {
2906     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2907                                   mImpl->mEventData->mPreEditLength,
2908                                   DONT_UPDATE_INPUT_STYLE );
2909
2910     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2911     mImpl->mEventData->mPreEditLength = 0u;
2912   }
2913   else
2914   {
2915     // Remove the previous Selection.
2916     removedSelected = RemoveSelectedText();
2917
2918   }
2919
2920   Vector<Character> utf32Characters;
2921   Length characterCount = 0u;
2922
2923   if( !text.empty() )
2924   {
2925     //  Convert text into UTF-32
2926     utf32Characters.Resize( text.size() );
2927
2928     // This is a bit horrible but std::string returns a (signed) char*
2929     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2930
2931     // Transform a text array encoded in utf8 into an array encoded in utf32.
2932     // It returns the actual number of characters.
2933     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2934     utf32Characters.Resize( characterCount );
2935
2936     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2937     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2938   }
2939
2940   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2941   {
2942     // The placeholder text is no longer needed
2943     if( mImpl->IsShowingPlaceholderText() )
2944     {
2945       ResetText();
2946     }
2947
2948     mImpl->ChangeState( EventData::EDITING );
2949
2950     // Handle the IMF (predicitive text) state changes
2951     if( COMMIT == type )
2952     {
2953       // IMF manager is no longer handling key-events
2954       mImpl->ClearPreEditFlag();
2955     }
2956     else // PRE_EDIT
2957     {
2958       if( !mImpl->mEventData->mPreEditFlag )
2959       {
2960         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2961
2962         // Record the start of the pre-edit text
2963         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2964       }
2965
2966       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2967       mImpl->mEventData->mPreEditFlag = true;
2968
2969       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2970     }
2971
2972     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2973
2974     // Restrict new text to fit within Maximum characters setting.
2975     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2976     maxLengthReached = ( characterCount > maxSizeOfNewText );
2977
2978     // The cursor position.
2979     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2980
2981     // Update the text's style.
2982
2983     // Updates the text style runs by adding characters.
2984     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2985
2986     // Get the character index from the cursor index.
2987     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2988
2989     // Retrieve the text's style for the given index.
2990     InputStyle style;
2991     mImpl->RetrieveDefaultInputStyle( style );
2992     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
2993
2994     // Whether to add a new text color run.
2995     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
2996
2997     // Whether to add a new font run.
2998     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
2999     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
3000     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
3001     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
3002     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
3003
3004     // Add style runs.
3005     if( addColorRun )
3006     {
3007       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3008       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3009
3010       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3011       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3012       colorRun.characterRun.characterIndex = cursorIndex;
3013       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3014     }
3015
3016     if( addFontNameRun   ||
3017         addFontWeightRun ||
3018         addFontWidthRun  ||
3019         addFontSlantRun  ||
3020         addFontSizeRun )
3021     {
3022       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3023       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3024
3025       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3026
3027       if( addFontNameRun )
3028       {
3029         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3030         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3031         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3032         fontDescriptionRun.familyDefined = true;
3033
3034         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3035       }
3036
3037       if( addFontWeightRun )
3038       {
3039         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3040         fontDescriptionRun.weightDefined = true;
3041       }
3042
3043       if( addFontWidthRun )
3044       {
3045         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3046         fontDescriptionRun.widthDefined = true;
3047       }
3048
3049       if( addFontSlantRun )
3050       {
3051         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3052         fontDescriptionRun.slantDefined = true;
3053       }
3054
3055       if( addFontSizeRun )
3056       {
3057         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3058         fontDescriptionRun.sizeDefined = true;
3059       }
3060
3061       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3062       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3063     }
3064
3065     // Insert at current cursor position.
3066     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3067
3068     if( cursorIndex < numberOfCharactersInModel )
3069     {
3070       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3071     }
3072     else
3073     {
3074       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3075     }
3076
3077     // Mark the first paragraph to be updated.
3078     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3079     {
3080       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3081       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3082       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3083       mImpl->mTextUpdateInfo.mClearAll = true;
3084     }
3085     else
3086     {
3087       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3088       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3089     }
3090
3091     // Update the cursor index.
3092     cursorIndex += maxSizeOfNewText;
3093
3094     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 );
3095   }
3096
3097   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3098       mImpl->IsPlaceholderAvailable() )
3099   {
3100     // Show place-holder if empty after removing the pre-edit text
3101     ShowPlaceholderText();
3102     mImpl->mEventData->mUpdateCursorPosition = true;
3103     mImpl->ClearPreEditFlag();
3104   }
3105   else if( removedPrevious ||
3106            removedSelected ||
3107            ( 0 != utf32Characters.Count() ) )
3108   {
3109     // Queue an inserted event
3110     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3111
3112     mImpl->mEventData->mUpdateCursorPosition = true;
3113     if( removedSelected )
3114     {
3115       mImpl->mEventData->mScrollAfterDelete = true;
3116     }
3117     else
3118     {
3119       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3120     }
3121   }
3122
3123   if( maxLengthReached )
3124   {
3125     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3126
3127     mImpl->ResetImfManager();
3128
3129     if( NULL != mImpl->mEditableControlInterface )
3130     {
3131       // Do this last since it provides callbacks into application code
3132       mImpl->mEditableControlInterface->MaxLengthReached();
3133     }
3134   }
3135 }
3136
3137 void Controller::PasteText( const std::string& stringToPaste )
3138 {
3139   InsertText( stringToPaste, Text::Controller::COMMIT );
3140   mImpl->ChangeState( EventData::EDITING );
3141   mImpl->RequestRelayout();
3142
3143   if( NULL != mImpl->mEditableControlInterface )
3144   {
3145     // Do this last since it provides callbacks into application code
3146     mImpl->mEditableControlInterface->TextChanged();
3147   }
3148 }
3149
3150 bool Controller::RemoveText( int cursorOffset,
3151                              int numberOfCharacters,
3152                              UpdateInputStyleType type )
3153 {
3154   bool removed = false;
3155
3156   if( NULL == mImpl->mEventData )
3157   {
3158     return removed;
3159   }
3160
3161   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3162                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3163
3164   if( !mImpl->IsShowingPlaceholderText() )
3165   {
3166     // Delete at current cursor position
3167     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3168     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3169
3170     CharacterIndex cursorIndex = 0;
3171
3172     // Validate the cursor position & number of characters
3173     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3174     {
3175       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3176     }
3177
3178     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3179     {
3180       numberOfCharacters = currentText.Count() - cursorIndex;