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