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