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