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