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