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