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