f96c97677942b5a2ec049998d3f1691e7c7c45a6
[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       if(EventData::SELECTING == mImpl->mEventData->mState)
1282       {
1283         const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1284
1285         // Get start and end position of selection
1286         const CharacterIndex startOfSelectedText  = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1287         const Length         lengthOfSelectedText = (handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition) - startOfSelectedText;
1288
1289         // Add the color run.
1290         const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1291         mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
1292
1293         ColorRun& colorRun                       = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
1294         colorRun.color                           = color;
1295         colorRun.characterRun.characterIndex     = startOfSelectedText;
1296         colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1297
1298         mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
1299         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1300         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
1301       }
1302       else
1303       {
1304         mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
1305         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1306         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
1307       }
1308
1309       // Request to relayout.
1310       mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
1311       mImpl->RequestRelayout();
1312     }
1313   }
1314 }
1315
1316 const Vector4& Controller::GetInputColor() const
1317 {
1318   if(NULL != mImpl->mEventData)
1319   {
1320     return mImpl->mEventData->mInputStyle.textColor;
1321   }
1322
1323   // Return the default text's color if there is no EventData.
1324   return mImpl->mTextColor;
1325 }
1326
1327 void Controller::SetInputFontFamily(const std::string& fontFamily)
1328 {
1329   InputFontHandler::SetInputFontFamily(*this, fontFamily);
1330 }
1331
1332 const std::string& Controller::GetInputFontFamily() const
1333 {
1334   return InputFontHandler::GetInputFontFamily(*this);
1335 }
1336
1337 void Controller::SetInputFontWeight(FontWeight weight)
1338 {
1339   InputFontHandler::SetInputFontWeight(*this, weight);
1340 }
1341
1342 bool Controller::IsInputFontWeightDefined() const
1343 {
1344   return InputFontHandler::IsInputFontWeightDefined(*this);
1345 }
1346
1347 FontWeight Controller::GetInputFontWeight() const
1348 {
1349   return InputFontHandler::GetInputFontWeight(*this);
1350 }
1351
1352 void Controller::SetInputFontWidth(FontWidth width)
1353 {
1354   InputFontHandler::SetInputFontWidth(*this, width);
1355 }
1356
1357 bool Controller::IsInputFontWidthDefined() const
1358 {
1359   return InputFontHandler::IsInputFontWidthDefined(*this);
1360 }
1361
1362 FontWidth Controller::GetInputFontWidth() const
1363 {
1364   return InputFontHandler::GetInputFontWidth(*this);
1365 }
1366
1367 void Controller::SetInputFontSlant(FontSlant slant)
1368 {
1369   InputFontHandler::SetInputFontSlant(*this, slant);
1370 }
1371
1372 bool Controller::IsInputFontSlantDefined() const
1373 {
1374   return InputFontHandler::IsInputFontSlantDefined(*this);
1375 }
1376
1377 FontSlant Controller::GetInputFontSlant() const
1378 {
1379   return InputFontHandler::GetInputFontSlant(*this);
1380 }
1381
1382 void Controller::SetInputFontPointSize(float size)
1383 {
1384   InputFontHandler::SetInputFontPointSize(*this, size);
1385 }
1386
1387 float Controller::GetInputFontPointSize() const
1388 {
1389   return InputFontHandler::GetInputFontPointSize(*this);
1390 }
1391
1392 void Controller::SetInputLineSpacing(float lineSpacing)
1393 {
1394   if(NULL != mImpl->mEventData)
1395   {
1396     mImpl->mEventData->mInputStyle.lineSpacing          = lineSpacing;
1397     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1398   }
1399 }
1400
1401 float Controller::GetInputLineSpacing() const
1402 {
1403   if(NULL != mImpl->mEventData)
1404   {
1405     return mImpl->mEventData->mInputStyle.lineSpacing;
1406   }
1407
1408   return 0.f;
1409 }
1410
1411 void Controller::SetInputShadowProperties(const std::string& shadowProperties)
1412 {
1413   if(NULL != mImpl->mEventData)
1414   {
1415     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1416   }
1417 }
1418
1419 const std::string& Controller::GetInputShadowProperties() const
1420 {
1421   if(NULL != mImpl->mEventData)
1422   {
1423     return mImpl->mEventData->mInputStyle.shadowProperties;
1424   }
1425
1426   return EMPTY_STRING;
1427 }
1428
1429 void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
1430 {
1431   if(NULL != mImpl->mEventData)
1432   {
1433     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1434   }
1435 }
1436
1437 const std::string& Controller::GetInputUnderlineProperties() const
1438 {
1439   if(NULL != mImpl->mEventData)
1440   {
1441     return mImpl->mEventData->mInputStyle.underlineProperties;
1442   }
1443
1444   return EMPTY_STRING;
1445 }
1446
1447 void Controller::SetInputEmbossProperties(const std::string& embossProperties)
1448 {
1449   if(NULL != mImpl->mEventData)
1450   {
1451     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1452   }
1453 }
1454
1455 const std::string& Controller::GetInputEmbossProperties() const
1456 {
1457   if(NULL != mImpl->mEventData)
1458   {
1459     return mImpl->mEventData->mInputStyle.embossProperties;
1460   }
1461
1462   return GetDefaultEmbossProperties();
1463 }
1464
1465 void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
1466 {
1467   if(NULL != mImpl->mEventData)
1468   {
1469     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1470   }
1471 }
1472
1473 const std::string& Controller::GetInputOutlineProperties() const
1474 {
1475   if(NULL != mImpl->mEventData)
1476   {
1477     return mImpl->mEventData->mInputStyle.outlineProperties;
1478   }
1479
1480   return GetDefaultOutlineProperties();
1481 }
1482
1483 void Controller::SetInputModePassword(bool passwordInput)
1484 {
1485   if(NULL != mImpl->mEventData)
1486   {
1487     mImpl->mEventData->mPasswordInput = passwordInput;
1488   }
1489 }
1490
1491 bool Controller::IsInputModePassword()
1492 {
1493   if(NULL != mImpl->mEventData)
1494   {
1495     return mImpl->mEventData->mPasswordInput;
1496   }
1497   return false;
1498 }
1499
1500 void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
1501 {
1502   if(NULL != mImpl->mEventData)
1503   {
1504     mImpl->mEventData->mDoubleTapAction = action;
1505   }
1506 }
1507
1508 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1509 {
1510   NoTextTap::Action action = NoTextTap::NO_ACTION;
1511
1512   if(NULL != mImpl->mEventData)
1513   {
1514     action = mImpl->mEventData->mDoubleTapAction;
1515   }
1516
1517   return action;
1518 }
1519
1520 void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
1521 {
1522   if(NULL != mImpl->mEventData)
1523   {
1524     mImpl->mEventData->mLongPressAction = action;
1525   }
1526 }
1527
1528 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1529 {
1530   NoTextTap::Action action = NoTextTap::NO_ACTION;
1531
1532   if(NULL != mImpl->mEventData)
1533   {
1534     action = mImpl->mEventData->mLongPressAction;
1535   }
1536
1537   return action;
1538 }
1539
1540 bool Controller::IsUnderlineSetByString()
1541 {
1542   return mImpl->mUnderlineSetByString;
1543 }
1544
1545 void Controller::UnderlineSetByString(bool setByString)
1546 {
1547   mImpl->mUnderlineSetByString = setByString;
1548 }
1549
1550 bool Controller::IsShadowSetByString()
1551 {
1552   return mImpl->mShadowSetByString;
1553 }
1554
1555 void Controller::ShadowSetByString(bool setByString)
1556 {
1557   mImpl->mShadowSetByString = setByString;
1558 }
1559
1560 bool Controller::IsOutlineSetByString()
1561 {
1562   return mImpl->mOutlineSetByString;
1563 }
1564
1565 void Controller::OutlineSetByString(bool setByString)
1566 {
1567   mImpl->mOutlineSetByString = setByString;
1568 }
1569
1570 bool Controller::IsFontStyleSetByString()
1571 {
1572   return mImpl->mFontStyleSetByString;
1573 }
1574
1575 void Controller::FontStyleSetByString(bool setByString)
1576 {
1577   mImpl->mFontStyleSetByString = setByString;
1578 }
1579
1580 // public : Queries & retrieves.
1581
1582 Layout::Engine& Controller::GetLayoutEngine()
1583 {
1584   return mImpl->mLayoutEngine;
1585 }
1586
1587 View& Controller::GetView()
1588 {
1589   return mImpl->mView;
1590 }
1591
1592 Vector3 Controller::GetNaturalSize()
1593 {
1594   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
1595   Vector3 naturalSize;
1596
1597   // Make sure the model is up-to-date before layouting
1598   ProcessModifyEvents();
1599
1600   if(mImpl->mRecalculateNaturalSize)
1601   {
1602     // Operations that can be done only once until the text changes.
1603     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1604                                                                           GET_SCRIPTS |
1605                                                                           VALIDATE_FONTS |
1606                                                                           GET_LINE_BREAKS |
1607                                                                           BIDI_INFO |
1608                                                                           SHAPE_TEXT |
1609                                                                           GET_GLYPH_METRICS);
1610
1611     // Set the update info to relayout the whole text.
1612     mImpl->mTextUpdateInfo.mParagraphCharacterIndex     = 0u;
1613     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1614
1615     // Make sure the model is up-to-date before layouting
1616     mImpl->UpdateModel(onlyOnceOperations);
1617
1618     // Layout the text for the new width.
1619     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT | REORDER);
1620
1621     // Store the actual control's size to restore later.
1622     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1623
1624     DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1625                static_cast<OperationsMask>(onlyOnceOperations |
1626                                            LAYOUT | REORDER),
1627                naturalSize.GetVectorXY());
1628
1629     // Do not do again the only once operations.
1630     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1631
1632     // Do the size related operations again.
1633     const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1634                                                                       ALIGN |
1635                                                                       REORDER);
1636     mImpl->mOperationsPending           = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1637
1638     // Stores the natural size to avoid recalculate it again
1639     // unless the text/style changes.
1640     mImpl->mModel->mVisualModel->SetNaturalSize(naturalSize.GetVectorXY());
1641
1642     mImpl->mRecalculateNaturalSize = false;
1643
1644     // Clear the update info. This info will be set the next time the text is updated.
1645     mImpl->mTextUpdateInfo.Clear();
1646     mImpl->mTextUpdateInfo.mClearAll = true;
1647
1648     // Restore the actual control's size.
1649     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1650
1651     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1652   }
1653   else
1654   {
1655     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1656
1657     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1658   }
1659
1660   naturalSize.x = ConvertToEven(naturalSize.x);
1661   naturalSize.y = ConvertToEven(naturalSize.y);
1662
1663   return naturalSize;
1664 }
1665
1666 bool Controller::CheckForTextFit(float pointSize, Size& layoutSize)
1667 {
1668   Size textSize;
1669   mImpl->mFontDefaults->mFitPointSize = pointSize;
1670   mImpl->mFontDefaults->sizeDefined   = true;
1671   ClearFontData();
1672
1673   // Operations that can be done only once until the text changes.
1674   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1675                                                                         GET_SCRIPTS |
1676                                                                         VALIDATE_FONTS |
1677                                                                         GET_LINE_BREAKS |
1678                                                                         BIDI_INFO |
1679                                                                         SHAPE_TEXT |
1680                                                                         GET_GLYPH_METRICS);
1681
1682   mImpl->mTextUpdateInfo.mParagraphCharacterIndex     = 0u;
1683   mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1684
1685   // Make sure the model is up-to-date before layouting
1686   mImpl->UpdateModel(onlyOnceOperations);
1687
1688   DoRelayout(Size(layoutSize.width, MAX_FLOAT),
1689              static_cast<OperationsMask>(onlyOnceOperations | LAYOUT),
1690              textSize);
1691
1692   // Clear the update info. This info will be set the next time the text is updated.
1693   mImpl->mTextUpdateInfo.Clear();
1694   mImpl->mTextUpdateInfo.mClearAll = true;
1695
1696   if(textSize.width > layoutSize.width || textSize.height > layoutSize.height)
1697   {
1698     return false;
1699   }
1700   return true;
1701 }
1702
1703 void Controller::FitPointSizeforLayout(Size layoutSize)
1704 {
1705   const OperationsMask operations = mImpl->mOperationsPending;
1706   if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations) || mImpl->mTextFitContentSize != layoutSize)
1707   {
1708     bool  actualellipsis = mImpl->mModel->mElideEnabled;
1709     float minPointSize   = mImpl->mTextFitMinSize;
1710     float maxPointSize   = mImpl->mTextFitMaxSize;
1711     float pointInterval  = mImpl->mTextFitStepSize;
1712
1713     mImpl->mModel->mElideEnabled = false;
1714     Vector<float> pointSizeArray;
1715
1716     // check zero value
1717     if(pointInterval < 1.f)
1718     {
1719       mImpl->mTextFitStepSize = pointInterval = 1.0f;
1720     }
1721
1722     pointSizeArray.Reserve(static_cast<unsigned int>(ceil((maxPointSize - minPointSize) / pointInterval)));
1723
1724     for(float i = minPointSize; i < maxPointSize; i += pointInterval)
1725     {
1726       pointSizeArray.PushBack(i);
1727     }
1728
1729     pointSizeArray.PushBack(maxPointSize);
1730
1731     int bestSizeIndex = 0;
1732     int min           = bestSizeIndex + 1;
1733     int max           = pointSizeArray.Size() - 1;
1734     while(min <= max)
1735     {
1736       int destI = (min + max) / 2;
1737
1738       if(CheckForTextFit(pointSizeArray[destI], layoutSize))
1739       {
1740         bestSizeIndex = min;
1741         min           = destI + 1;
1742       }
1743       else
1744       {
1745         max           = destI - 1;
1746         bestSizeIndex = max;
1747       }
1748     }
1749
1750     mImpl->mModel->mElideEnabled        = actualellipsis;
1751     mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
1752     mImpl->mFontDefaults->sizeDefined   = true;
1753     ClearFontData();
1754   }
1755 }
1756
1757 float Controller::GetHeightForWidth(float width)
1758 {
1759   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width);
1760   // Make sure the model is up-to-date before layouting
1761   ProcessModifyEvents();
1762
1763   Size layoutSize;
1764   if(fabsf(width - mImpl->mModel->mVisualModel->mControlSize.width) > Math::MACHINE_EPSILON_1000 ||
1765      mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1766      mImpl->mTextUpdateInfo.mClearAll)
1767   {
1768     // Operations that can be done only once until the text changes.
1769     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1770                                                                           GET_SCRIPTS |
1771                                                                           VALIDATE_FONTS |
1772                                                                           GET_LINE_BREAKS |
1773                                                                           BIDI_INFO |
1774                                                                           SHAPE_TEXT |
1775                                                                           GET_GLYPH_METRICS);
1776
1777     // Set the update info to relayout the whole text.
1778     mImpl->mTextUpdateInfo.mParagraphCharacterIndex     = 0u;
1779     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1780
1781     // Make sure the model is up-to-date before layouting
1782     mImpl->UpdateModel(onlyOnceOperations);
1783
1784     // Layout the text for the new width.
1785     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT);
1786
1787     // Store the actual control's width.
1788     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1789
1790     DoRelayout(Size(width, MAX_FLOAT),
1791                static_cast<OperationsMask>(onlyOnceOperations |
1792                                            LAYOUT),
1793                layoutSize);
1794
1795     // Do not do again the only once operations.
1796     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1797
1798     // Do the size related operations again.
1799     const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1800                                                                       ALIGN |
1801                                                                       REORDER);
1802
1803     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1804
1805     // Clear the update info. This info will be set the next time the text is updated.
1806     mImpl->mTextUpdateInfo.Clear();
1807     mImpl->mTextUpdateInfo.mClearAll = true;
1808
1809     // Restore the actual control's width.
1810     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1811
1812     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
1813   }
1814   else
1815   {
1816     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1817     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height);
1818   }
1819
1820   return layoutSize.height;
1821 }
1822
1823 int Controller::GetLineCount(float width)
1824 {
1825   GetHeightForWidth(width);
1826   int numberofLines = mImpl->mModel->GetNumberOfLines();
1827   return numberofLines;
1828 }
1829
1830 const ModelInterface* const Controller::GetTextModel() const
1831 {
1832   return mImpl->mModel.Get();
1833 }
1834
1835 float Controller::GetScrollAmountByUserInput()
1836 {
1837   float scrollAmount = 0.0f;
1838
1839   if(NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1840   {
1841     scrollAmount                          = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
1842     mImpl->mEventData->mCheckScrollAmount = false;
1843   }
1844   return scrollAmount;
1845 }
1846
1847 bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight)
1848 {
1849   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1850   bool           isScrolled;
1851
1852   controlHeight  = mImpl->mModel->mVisualModel->mControlSize.height;
1853   layoutHeight   = layout.height;
1854   scrollPosition = mImpl->mModel->mScrollPosition.y;
1855   isScrolled     = !Equals(mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1);
1856   return isScrolled;
1857 }
1858
1859 void Controller::SetHiddenInputOption(const Property::Map& options)
1860 {
1861   if(NULL == mImpl->mHiddenInput)
1862   {
1863     mImpl->mHiddenInput = new HiddenText(this);
1864   }
1865   mImpl->mHiddenInput->SetProperties(options);
1866 }
1867
1868 void Controller::GetHiddenInputOption(Property::Map& options)
1869 {
1870   if(NULL != mImpl->mHiddenInput)
1871   {
1872     mImpl->mHiddenInput->GetProperties(options);
1873   }
1874 }
1875
1876 void Controller::SetPlaceholderProperty(const Property::Map& map)
1877 {
1878   PlaceholderHandler::SetPlaceholderProperty(*this, map);
1879 }
1880
1881 void Controller::GetPlaceholderProperty(Property::Map& map)
1882 {
1883   PlaceholderHandler::GetPlaceholderProperty(*this, map);
1884 }
1885
1886 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
1887 {
1888   // Make sure the model is up-to-date before layouting
1889   ProcessModifyEvents();
1890
1891   if(mImpl->mUpdateTextDirection)
1892   {
1893     // Operations that can be done only once until the text changes.
1894     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1895                                                                           GET_SCRIPTS |
1896                                                                           VALIDATE_FONTS |
1897                                                                           GET_LINE_BREAKS |
1898                                                                           BIDI_INFO |
1899                                                                           SHAPE_TEXT |
1900                                                                           GET_GLYPH_METRICS);
1901
1902     // Set the update info to relayout the whole text.
1903     mImpl->mTextUpdateInfo.mParagraphCharacterIndex     = 0u;
1904     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1905
1906     // Make sure the model is up-to-date before layouting
1907     mImpl->UpdateModel(onlyOnceOperations);
1908
1909     Vector3 naturalSize;
1910     DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1911                static_cast<OperationsMask>(onlyOnceOperations |
1912                                            LAYOUT | REORDER | UPDATE_DIRECTION),
1913                naturalSize.GetVectorXY());
1914
1915     // Do not do again the only once operations.
1916     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1917
1918     // Clear the update info. This info will be set the next time the text is updated.
1919     mImpl->mTextUpdateInfo.Clear();
1920
1921     // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
1922     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1923
1924     mImpl->mUpdateTextDirection = false;
1925   }
1926
1927   return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
1928 }
1929
1930 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
1931 {
1932   return mImpl->mModel->GetVerticalLineAlignment();
1933 }
1934
1935 void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment)
1936 {
1937   mImpl->mModel->mVerticalLineAlignment = alignment;
1938 }
1939
1940 // public : Relayout.
1941
1942 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
1943 {
1944   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ? "true" : "false");
1945
1946   UpdateTextType updateTextType = NONE_UPDATED;
1947
1948   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
1949   {
1950     if(0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count())
1951     {
1952       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
1953       updateTextType = MODEL_UPDATED;
1954     }
1955
1956     // Clear the update info. This info will be set the next time the text is updated.
1957     mImpl->mTextUpdateInfo.Clear();
1958
1959     // Not worth to relayout if width or height is equal to zero.
1960     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n");
1961
1962     return updateTextType;
1963   }
1964
1965   // Whether a new size has been set.
1966   const bool newSize = (size != mImpl->mModel->mVisualModel->mControlSize);
1967
1968   if(newSize)
1969   {
1970     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height);
1971
1972     if((0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd) &&
1973        (0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters) &&
1974        ((mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
1975     {
1976       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
1977     }
1978
1979     // Layout operations that need to be done if the size changes.
1980     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
1981                                                             LAYOUT |
1982                                                             ALIGN |
1983                                                             UPDATE_LAYOUT_SIZE |
1984                                                             REORDER);
1985     // Set the update info to relayout the whole text.
1986     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1987     mImpl->mTextUpdateInfo.mCharacterIndex     = 0u;
1988
1989     // Store the size used to layout the text.
1990     mImpl->mModel->mVisualModel->mControlSize = size;
1991   }
1992
1993   // Whether there are modify events.
1994   if(0u != mImpl->mModifyEvents.Count())
1995   {
1996     // Style operations that need to be done if the text is modified.
1997     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
1998                                                             COLOR);
1999   }
2000
2001   // Set the update info to elide the text.
2002   if(mImpl->mModel->mElideEnabled ||
2003      ((NULL != mImpl->mEventData) && mImpl->mEventData->mIsPlaceholderElideEnabled))
2004   {
2005     // Update Text layout for applying elided
2006     mImpl->mOperationsPending                  = static_cast<OperationsMask>(mImpl->mOperationsPending |
2007                                                             ALIGN |
2008                                                             LAYOUT |
2009                                                             UPDATE_LAYOUT_SIZE |
2010                                                             REORDER);
2011     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2012     mImpl->mTextUpdateInfo.mCharacterIndex     = 0u;
2013   }
2014
2015   if(mImpl->mModel->mMatchSystemLanguageDirection && mImpl->mLayoutDirection != layoutDirection)
2016   {
2017     // Clear the update info. This info will be set the next time the text is updated.
2018     mImpl->mTextUpdateInfo.mClearAll = true;
2019     // Apply modifications to the model
2020     // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
2021     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2022                                                             GET_GLYPH_METRICS |
2023                                                             SHAPE_TEXT |
2024                                                             UPDATE_DIRECTION |
2025                                                             LAYOUT |
2026                                                             BIDI_INFO |
2027                                                             REORDER);
2028     mImpl->mLayoutDirection   = layoutDirection;
2029   }
2030
2031   // Make sure the model is up-to-date before layouting.
2032   ProcessModifyEvents();
2033   bool updated = mImpl->UpdateModel(mImpl->mOperationsPending);
2034
2035   // Layout the text.
2036   Size layoutSize;
2037   updated = DoRelayout(size,
2038                        mImpl->mOperationsPending,
2039                        layoutSize) ||
2040             updated;
2041
2042   if(updated)
2043   {
2044     updateTextType = MODEL_UPDATED;
2045   }
2046
2047   // Do not re-do any operation until something changes.
2048   mImpl->mOperationsPending          = NO_OPERATION;
2049   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2050
2051   // Whether the text control is editable
2052   const bool isEditable = NULL != mImpl->mEventData;
2053
2054   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2055   Vector2 offset;
2056   if(newSize && isEditable)
2057   {
2058     offset = mImpl->mModel->mScrollPosition;
2059   }
2060
2061   if(!isEditable || !IsMultiLineEnabled())
2062   {
2063     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2064     CalculateVerticalOffset(size);
2065   }
2066
2067   if(isEditable)
2068   {
2069     if(newSize)
2070     {
2071       // If there is a new size, the scroll position needs to be clamped.
2072       mImpl->ClampHorizontalScroll(layoutSize);
2073
2074       // Update the decorator's positions is needed if there is a new size.
2075       mImpl->mEventData->mDecorator->UpdatePositions(mImpl->mModel->mScrollPosition - offset);
2076     }
2077
2078     // Move the cursor, grab handle etc.
2079     if(mImpl->ProcessInputEvents())
2080     {
2081       updateTextType = static_cast<UpdateTextType>(updateTextType | DECORATOR_UPDATED);
2082     }
2083   }
2084
2085   // Clear the update info. This info will be set the next time the text is updated.
2086   mImpl->mTextUpdateInfo.Clear();
2087   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout\n");
2088
2089   return updateTextType;
2090 }
2091
2092 void Controller::RequestRelayout()
2093 {
2094   mImpl->RequestRelayout();
2095 }
2096
2097 // public : Input style change signals.
2098
2099 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2100 {
2101   return (NULL == mImpl->mEventData) || (0u == mImpl->mEventData->mInputStyleChangedQueue.Count());
2102 }
2103
2104 void Controller::ProcessInputStyleChangedSignals()
2105 {
2106   if(NULL == mImpl->mEventData)
2107   {
2108     // Nothing to do.
2109     return;
2110   }
2111
2112   for(Vector<InputStyle::Mask>::ConstIterator it    = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2113                                               endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2114       it != endIt;
2115       ++it)
2116   {
2117     const InputStyle::Mask mask = *it;
2118
2119     if(NULL != mImpl->mEditableControlInterface)
2120     {
2121       // Emit the input style changed signal.
2122       mImpl->mEditableControlInterface->InputStyleChanged(mask);
2123     }
2124   }
2125
2126   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2127 }
2128
2129 // public : Text-input Event Queuing.
2130
2131 void Controller::KeyboardFocusGainEvent()
2132 {
2133   EventHandler::KeyboardFocusGainEvent(*this);
2134 }
2135
2136 void Controller::KeyboardFocusLostEvent()
2137 {
2138   EventHandler::KeyboardFocusLostEvent(*this);
2139 }
2140
2141 bool Controller::KeyEvent(const Dali::KeyEvent& keyEvent)
2142 {
2143   return EventHandler::KeyEvent(*this, keyEvent);
2144 }
2145
2146 void Controller::TapEvent(unsigned int tapCount, float x, float y)
2147 {
2148   EventHandler::TapEvent(*this, tapCount, x, y);
2149 }
2150
2151 void Controller::PanEvent(GestureState state, const Vector2& displacement)
2152 {
2153   EventHandler::PanEvent(*this, state, displacement);
2154 }
2155
2156 void Controller::LongPressEvent(GestureState state, float x, float y)
2157 {
2158   EventHandler::LongPressEvent(*this, state, x, y);
2159 }
2160
2161 void Controller::SelectEvent(float x, float y, SelectionType selectType)
2162 {
2163   EventHandler::SelectEvent(*this, x, y, selectType);
2164 }
2165
2166 void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
2167 {
2168   if(mImpl->mEventData)
2169   {
2170     mImpl->mEventData->mCheckScrollAmount     = true;
2171     mImpl->mEventData->mIsLeftHandleSelected  = true;
2172     mImpl->mEventData->mIsRightHandleSelected = true;
2173     mImpl->SetTextSelectionRange(start, end);
2174     mImpl->RequestRelayout();
2175     KeyboardFocusGainEvent();
2176   }
2177 }
2178
2179 Uint32Pair Controller::GetTextSelectionRange() const
2180 {
2181   return mImpl->GetTextSelectionRange();
2182 }
2183
2184 void Controller::SelectWholeText()
2185 {
2186   SelectEvent(0.f, 0.f, SelectionType::ALL);
2187 }
2188
2189 void Controller::SelectNone()
2190 {
2191   SelectEvent(0.f, 0.f, SelectionType::NONE);
2192 }
2193
2194 string Controller::GetSelectedText() const
2195 {
2196   string text;
2197   if(EventData::SELECTING == mImpl->mEventData->mState)
2198   {
2199     mImpl->RetrieveSelection(text, false);
2200   }
2201   return text;
2202 }
2203
2204 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
2205 {
2206   return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
2207 }
2208
2209 void Controller::PasteClipboardItemEvent()
2210 {
2211   EventHandler::PasteClipboardItemEvent(*this);
2212 }
2213
2214 // protected : Inherit from Text::Decorator::ControllerInterface.
2215
2216 void Controller::GetTargetSize(Vector2& targetSize)
2217 {
2218   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2219 }
2220
2221 void Controller::AddDecoration(Actor& actor, bool needsClipping)
2222 {
2223   if(NULL != mImpl->mEditableControlInterface)
2224   {
2225     mImpl->mEditableControlInterface->AddDecoration(actor, needsClipping);
2226   }
2227 }
2228
2229 bool Controller::IsEditable() const
2230 {
2231   return mImpl->IsEditable();
2232 }
2233
2234 void Controller::SetEditable(bool editable)
2235 {
2236   mImpl->SetEditable(editable);
2237   if(mImpl->mEventData && mImpl->mEventData->mDecorator)
2238   {
2239     mImpl->mEventData->mDecorator->SetEditable(editable);
2240   }
2241 }
2242
2243 void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
2244 {
2245   EventHandler::DecorationEvent(*this, handleType, state, x, y);
2246 }
2247
2248 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2249
2250 void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
2251 {
2252   EventHandler::TextPopupButtonTouched(*this, button);
2253 }
2254
2255 void Controller::DisplayTimeExpired()
2256 {
2257   mImpl->mEventData->mUpdateCursorPosition = true;
2258   // Apply modifications to the model
2259   mImpl->mOperationsPending = ALL_OPERATIONS;
2260
2261   mImpl->RequestRelayout();
2262 }
2263
2264 // private : Update.
2265
2266 void Controller::InsertText(const std::string& text, Controller::InsertType type)
2267 {
2268   bool removedPrevious  = false;
2269   bool removedSelected  = false;
2270   bool maxLengthReached = false;
2271
2272   DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "Unexpected InsertText")
2273
2274   if(NULL == mImpl->mEventData)
2275   {
2276     return;
2277   }
2278
2279   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);
2280
2281   // TODO: At the moment the underline runs are only for pre-edit.
2282   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2283
2284   // Remove the previous InputMethodContext pre-edit.
2285   if(mImpl->mEventData->mPreEditFlag && (0u != mImpl->mEventData->mPreEditLength))
2286   {
2287     removedPrevious = RemoveText(-static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition),
2288                                  mImpl->mEventData->mPreEditLength,
2289                                  DONT_UPDATE_INPUT_STYLE);
2290
2291     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2292     mImpl->mEventData->mPreEditLength         = 0u;
2293   }
2294   else
2295   {
2296     // Remove the previous Selection.
2297     removedSelected = RemoveSelectedText();
2298   }
2299
2300   Vector<Character> utf32Characters;
2301   Length            characterCount = 0u;
2302
2303   if(!text.empty())
2304   {
2305     //  Convert text into UTF-32
2306     utf32Characters.Resize(text.size());
2307
2308     // This is a bit horrible but std::string returns a (signed) char*
2309     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
2310
2311     // Transform a text array encoded in utf8 into an array encoded in utf32.
2312     // It returns the actual number of characters.
2313     characterCount = Utf8ToUtf32(utf8, text.size(), utf32Characters.Begin());
2314     utf32Characters.Resize(characterCount);
2315
2316     DALI_ASSERT_DEBUG(text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length");
2317     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count());
2318   }
2319
2320   if(0u != utf32Characters.Count()) // Check if Utf8ToUtf32 conversion succeeded
2321   {
2322     // The placeholder text is no longer needed
2323     if(mImpl->IsShowingPlaceholderText())
2324     {
2325       ResetText();
2326     }
2327
2328     mImpl->ChangeState(EventData::EDITING);
2329
2330     // Handle the InputMethodContext (predicitive text) state changes
2331     if(COMMIT == type)
2332     {
2333       // InputMethodContext is no longer handling key-events
2334       mImpl->ClearPreEditFlag();
2335     }
2336     else // PRE_EDIT
2337     {
2338       if(!mImpl->mEventData->mPreEditFlag)
2339       {
2340         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Entered PreEdit state\n");
2341
2342         // Record the start of the pre-edit text
2343         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2344       }
2345
2346       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2347       mImpl->mEventData->mPreEditFlag   = true;
2348
2349       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength);
2350     }
2351
2352     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2353
2354     // Restrict new text to fit within Maximum characters setting.
2355     Length maxSizeOfNewText = std::min((mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel), characterCount);
2356     maxLengthReached        = (characterCount > maxSizeOfNewText);
2357
2358     // The cursor position.
2359     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2360
2361     // Update the text's style.
2362
2363     // Updates the text style runs by adding characters.
2364     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, maxSizeOfNewText);
2365
2366     // Get the character index from the cursor index.
2367     const CharacterIndex styleIndex = (cursorIndex > 0u) ? cursorIndex - 1u : 0u;
2368
2369     // Retrieve the text's style for the given index.
2370     InputStyle style;
2371     mImpl->RetrieveDefaultInputStyle(style);
2372     mImpl->mModel->mLogicalModel->RetrieveStyle(styleIndex, style);
2373
2374     // Whether to add a new text color run.
2375     const bool addColorRun = (style.textColor != mImpl->mEventData->mInputStyle.textColor) && !mImpl->mEventData->mInputStyle.isDefaultColor;
2376
2377     // Whether to add a new font run.
2378     const bool addFontNameRun   = (style.familyName != mImpl->mEventData->mInputStyle.familyName) && mImpl->mEventData->mInputStyle.isFamilyDefined;
2379     const bool addFontWeightRun = (style.weight != mImpl->mEventData->mInputStyle.weight) && mImpl->mEventData->mInputStyle.isWeightDefined;
2380     const bool addFontWidthRun  = (style.width != mImpl->mEventData->mInputStyle.width) && mImpl->mEventData->mInputStyle.isWidthDefined;
2381     const bool addFontSlantRun  = (style.slant != mImpl->mEventData->mInputStyle.slant) && mImpl->mEventData->mInputStyle.isSlantDefined;
2382     const bool addFontSizeRun   = (style.size != mImpl->mEventData->mInputStyle.size) && mImpl->mEventData->mInputStyle.isSizeDefined;
2383
2384     // Add style runs.
2385     if(addColorRun)
2386     {
2387       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2388       mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
2389
2390       ColorRun& colorRun                       = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
2391       colorRun.color                           = mImpl->mEventData->mInputStyle.textColor;
2392       colorRun.characterRun.characterIndex     = cursorIndex;
2393       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2394     }
2395
2396     if(addFontNameRun ||
2397        addFontWeightRun ||
2398        addFontWidthRun ||
2399        addFontSlantRun ||
2400        addFontSizeRun)
2401     {
2402       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2403       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
2404
2405       FontDescriptionRun& fontDescriptionRun = *(mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
2406
2407       if(addFontNameRun)
2408       {
2409         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2410         fontDescriptionRun.familyName   = new char[fontDescriptionRun.familyLength];
2411         memcpy(fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength);
2412         fontDescriptionRun.familyDefined = true;
2413
2414         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2415       }
2416
2417       if(addFontWeightRun)
2418       {
2419         fontDescriptionRun.weight        = mImpl->mEventData->mInputStyle.weight;
2420         fontDescriptionRun.weightDefined = true;
2421       }
2422
2423       if(addFontWidthRun)
2424       {
2425         fontDescriptionRun.width        = mImpl->mEventData->mInputStyle.width;
2426         fontDescriptionRun.widthDefined = true;
2427       }
2428
2429       if(addFontSlantRun)
2430       {
2431         fontDescriptionRun.slant        = mImpl->mEventData->mInputStyle.slant;
2432         fontDescriptionRun.slantDefined = true;
2433       }
2434
2435       if(addFontSizeRun)
2436       {
2437         fontDescriptionRun.size        = static_cast<PointSize26Dot6>(mImpl->mEventData->mInputStyle.size * 64.f);
2438         fontDescriptionRun.sizeDefined = true;
2439       }
2440
2441       fontDescriptionRun.characterRun.characterIndex     = cursorIndex;
2442       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2443     }
2444
2445     // Insert at current cursor position.
2446     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
2447
2448     if(cursorIndex < numberOfCharactersInModel)
2449     {
2450       modifyText.Insert(modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2451     }
2452     else
2453     {
2454       modifyText.Insert(modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2455     }
2456
2457     // Mark the first paragraph to be updated.
2458     if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2459     {
2460       mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
2461       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2462       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = numberOfCharactersInModel + maxSizeOfNewText;
2463       mImpl->mTextUpdateInfo.mClearAll                   = true;
2464     }
2465     else
2466     {
2467       mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2468       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2469     }
2470
2471     // Update the cursor index.
2472     cursorIndex += maxSizeOfNewText;
2473
2474     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);
2475   }
2476
2477   if((0u == mImpl->mModel->mLogicalModel->mText.Count()) &&
2478      mImpl->IsPlaceholderAvailable())
2479   {
2480     // Show place-holder if empty after removing the pre-edit text
2481     ShowPlaceholderText();
2482     mImpl->mEventData->mUpdateCursorPosition = true;
2483     mImpl->ClearPreEditFlag();
2484   }
2485   else if(removedPrevious ||
2486           removedSelected ||
2487           (0 != utf32Characters.Count()))
2488   {
2489     // Queue an inserted event
2490     mImpl->QueueModifyEvent(ModifyEvent::TEXT_INSERTED);
2491
2492     mImpl->mEventData->mUpdateCursorPosition = true;
2493     if(removedSelected)
2494     {
2495       mImpl->mEventData->mScrollAfterDelete = true;
2496     }
2497     else
2498     {
2499       mImpl->mEventData->mScrollAfterUpdatePosition = true;
2500     }
2501   }
2502
2503   if(maxLengthReached)
2504   {
2505     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count());
2506
2507     mImpl->ResetInputMethodContext();
2508
2509     if(NULL != mImpl->mEditableControlInterface)
2510     {
2511       // Do this last since it provides callbacks into application code
2512       mImpl->mEditableControlInterface->MaxLengthReached();
2513     }
2514   }
2515 }
2516
2517 void Controller::PasteText(const std::string& stringToPaste)
2518 {
2519   InsertText(stringToPaste, Text::Controller::COMMIT);
2520   mImpl->ChangeState(EventData::EDITING);
2521   mImpl->RequestRelayout();
2522
2523   if(NULL != mImpl->mEditableControlInterface)
2524   {
2525     // Do this last since it provides callbacks into application code
2526     mImpl->mEditableControlInterface->TextChanged(true);
2527   }
2528 }
2529
2530 bool Controller::RemoveText(int                  cursorOffset,
2531                             int                  numberOfCharacters,
2532                             UpdateInputStyleType type)
2533 {
2534   bool removed = false;
2535   bool removeAll = false;
2536
2537   if(NULL == mImpl->mEventData)
2538   {
2539     return removed;
2540   }
2541
2542   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);
2543
2544   if(!mImpl->IsShowingPlaceholderText())
2545   {
2546     // Delete at current cursor position
2547     Vector<Character>& currentText    = mImpl->mModel->mLogicalModel->mText;
2548     CharacterIndex&    oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2549
2550     CharacterIndex cursorIndex = 0;
2551
2552     // Validate the cursor position & number of characters
2553     if((static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition) + cursorOffset) >= 0)
2554     {
2555       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
2556     }
2557
2558     if((cursorIndex + numberOfCharacters) > currentText.Count())
2559     {
2560       numberOfCharacters = currentText.Count() - cursorIndex;
2561     }
2562
2563     if((cursorIndex == 0) && (currentText.Count() - numberOfCharacters == 0))
2564     {
2565       removeAll = true;
2566     }
2567
2568     if(mImpl->mEventData->mPreEditFlag || removeAll || // 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.
2569        ((cursorIndex + numberOfCharacters) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters))
2570     {
2571       // Mark the paragraphs to be updated.
2572       if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2573       {
2574         mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
2575         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2576         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
2577         mImpl->mTextUpdateInfo.mClearAll                   = true;
2578       }
2579       else
2580       {
2581         mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2582         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2583       }
2584
2585       // Update the input style and remove the text's style before removing the text.
2586
2587       if(UPDATE_INPUT_STYLE == type)
2588       {
2589         // Keep a copy of the current input style.
2590         InputStyle currentInputStyle;
2591         currentInputStyle.Copy(mImpl->mEventData->mInputStyle);
2592
2593         // Set first the default input style.
2594         mImpl->RetrieveDefaultInputStyle(mImpl->mEventData->mInputStyle);
2595
2596         // Update the input style.
2597         mImpl->mModel->mLogicalModel->RetrieveStyle(cursorIndex, mImpl->mEventData->mInputStyle);
2598
2599         // Compare if the input style has changed.
2600         const bool hasInputStyleChanged = !currentInputStyle.Equal(mImpl->mEventData->mInputStyle);
2601
2602         if(hasInputStyleChanged)
2603         {
2604           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mImpl->mEventData->mInputStyle);
2605           // Queue the input style changed signal.
2606           mImpl->mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
2607         }
2608       }
2609
2610       // If the number of current text and the number of characters to be deleted are same,
2611       // it means all texts should be removed and all Preedit variables should be initialized.
2612       if(removeAll)
2613       {
2614         mImpl->ClearPreEditFlag();
2615         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
2616       }
2617
2618       // Updates the text style runs by removing characters. Runs with no characters are removed.
2619       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, -numberOfCharacters);
2620
2621       // Remove the characters.
2622       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2623       Vector<Character>::Iterator last  = first + numberOfCharacters;
2624
2625       currentText.Erase(first, last);
2626
2627       // Cursor position retreat
2628       oldCursorIndex = cursorIndex;
2629
2630       mImpl->mEventData->mScrollAfterDelete = true;
2631
2632       if(EventData::INACTIVE == mImpl->mEventData->mState)
2633       {
2634         mImpl->ChangeState(EventData::EDITING);
2635       }
2636
2637       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters);
2638       removeAll = false;
2639       removed = true;
2640     }
2641   }
2642
2643   return removed;
2644 }
2645
2646 bool Controller::RemoveSelectedText()
2647 {
2648   bool textRemoved(false);
2649
2650   if(EventData::SELECTING == mImpl->mEventData->mState)
2651   {
2652     std::string removedString;
2653     mImpl->RetrieveSelection(removedString, true);
2654
2655     if(!removedString.empty())
2656     {
2657       textRemoved = true;
2658       mImpl->ChangeState(EventData::EDITING);
2659     }
2660   }
2661
2662   return textRemoved;
2663 }
2664
2665 // private : Relayout.
2666
2667 bool Controller::DoRelayout(const Size&    size,
2668                             OperationsMask operationsRequired,
2669                             Size&          layoutSize)
2670 {
2671   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height);
2672   bool viewUpdated(false);
2673
2674   // Calculate the operations to be done.
2675   const OperationsMask operations = static_cast<OperationsMask>(mImpl->mOperationsPending & operationsRequired);
2676
2677   const CharacterIndex startIndex                  = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
2678   const Length         requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
2679
2680   // Get the current layout size.
2681   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2682
2683   if(NO_OPERATION != (LAYOUT & operations))
2684   {
2685     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
2686
2687     // Some vectors with data needed to layout and reorder may be void
2688     // after the first time the text has been laid out.
2689     // Fill the vectors again.
2690
2691     // Calculate the number of glyphs to layout.
2692     const Vector<GlyphIndex>& charactersToGlyph        = mImpl->mModel->mVisualModel->mCharactersToGlyph;
2693     const Vector<Length>&     glyphsPerCharacter       = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
2694     const GlyphIndex* const   charactersToGlyphBuffer  = charactersToGlyph.Begin();
2695     const Length* const       glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
2696
2697     const CharacterIndex lastIndex       = startIndex + ((requestedNumberOfCharacters > 0u) ? requestedNumberOfCharacters - 1u : 0u);
2698     const GlyphIndex     startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
2699
2700     // Make sure the index is not out of bound
2701     if(charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
2702        requestedNumberOfCharacters > charactersToGlyph.Count() ||
2703        (lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u))
2704     {
2705       std::string currentText;
2706       GetText(currentText);
2707
2708       DALI_LOG_ERROR("Controller::DoRelayout: Attempting to access invalid buffer\n");
2709       DALI_LOG_ERROR("Current text is: %s\n", currentText.c_str());
2710       DALI_LOG_ERROR("startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
2711
2712       return false;
2713     }
2714
2715     const Length numberOfGlyphs      = (requestedNumberOfCharacters > 0u) ? *(charactersToGlyphBuffer + lastIndex) + *(glyphsPerCharacterBuffer + lastIndex) - startGlyphIndex : 0u;
2716     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
2717
2718     if(0u == totalNumberOfGlyphs)
2719     {
2720       if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2721       {
2722         mImpl->mModel->mVisualModel->SetLayoutSize(Size::ZERO);
2723       }
2724
2725       // Nothing else to do if there is no glyphs.
2726       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n");
2727       return true;
2728     }
2729
2730     // Set the layout parameters.
2731     Layout::Parameters layoutParameters(size,
2732                                         mImpl->mModel);
2733
2734     // Resize the vector of positions to have the same size than the vector of glyphs.
2735     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
2736     glyphPositions.Resize(totalNumberOfGlyphs);
2737
2738     // Whether the last character is a new paragraph character.
2739     const Character* const textBuffer                   = mImpl->mModel->mLogicalModel->mText.Begin();
2740     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph(*(textBuffer + (mImpl->mModel->mLogicalModel->mText.Count() - 1u)));
2741     layoutParameters.isLastNewParagraph                 = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
2742
2743     // The initial glyph and the number of glyphs to layout.
2744     layoutParameters.startGlyphIndex        = startGlyphIndex;
2745     layoutParameters.numberOfGlyphs         = numberOfGlyphs;
2746     layoutParameters.startLineIndex         = mImpl->mTextUpdateInfo.mStartLineIndex;
2747     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
2748
2749     // Update the ellipsis
2750     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
2751
2752     if(NULL != mImpl->mEventData)
2753     {
2754       if(mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText())
2755       {
2756         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
2757       }
2758       else if(EventData::INACTIVE != mImpl->mEventData->mState)
2759       {
2760         // Disable ellipsis when editing
2761         elideTextEnabled = false;
2762       }
2763
2764       // Reset the scroll position in inactive state
2765       if(elideTextEnabled && (mImpl->mEventData->mState == EventData::INACTIVE))
2766       {
2767         ResetScrollPosition();
2768       }
2769     }
2770
2771     // Update the visual model.
2772     bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
2773     Size newLayoutSize;
2774     viewUpdated                 = mImpl->mLayoutEngine.LayoutText(layoutParameters,
2775                                                   newLayoutSize,
2776                                                   elideTextEnabled,
2777                                                   isAutoScrollEnabled);
2778     mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
2779
2780     viewUpdated = viewUpdated || (newLayoutSize != layoutSize);
2781
2782     if(viewUpdated)
2783     {
2784       layoutSize = newLayoutSize;
2785
2786       if(NO_OPERATION != (UPDATE_DIRECTION & operations))
2787       {
2788         mImpl->mIsTextDirectionRTL = false;
2789       }
2790
2791       if((NO_OPERATION != (UPDATE_DIRECTION & operations)) && !mImpl->mModel->mVisualModel->mLines.Empty())
2792       {
2793         mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
2794       }
2795
2796       // Sets the layout size.
2797       if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2798       {
2799         mImpl->mModel->mVisualModel->SetLayoutSize(layoutSize);
2800       }
2801     } // view updated
2802   }
2803
2804   if(NO_OPERATION != (ALIGN & operations))
2805   {
2806     // The laid-out lines.
2807     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
2808
2809     CharacterIndex alignStartIndex                  = startIndex;
2810     Length         alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
2811
2812     // the whole text needs to be full aligned.
2813     // If you do not do a full aligned, only the last line of the multiline input is aligned.
2814     if(mImpl->mEventData && mImpl->mEventData->mUpdateAlignment)
2815     {
2816       alignStartIndex                     = 0u;
2817       alignRequestedNumberOfCharacters    = mImpl->mModel->mLogicalModel->mText.Count();
2818       mImpl->mEventData->mUpdateAlignment = false;
2819     }
2820
2821     // Need to align with the control's size as the text may contain lines
2822     // starting either with left to right text or right to left.
2823     mImpl->mLayoutEngine.Align(size,
2824                                alignStartIndex,
2825                                alignRequestedNumberOfCharacters,
2826                                mImpl->mModel->mHorizontalAlignment,
2827                                lines,
2828                                mImpl->mModel->mAlignmentOffset,
2829                                mImpl->mLayoutDirection,
2830                                mImpl->mModel->mMatchSystemLanguageDirection);
2831
2832     viewUpdated = true;
2833   }
2834 #if defined(DEBUG_ENABLED)
2835   std::string currentText;
2836   GetText(currentText);
2837   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL) ? "true" : "false", currentText.c_str());
2838 #endif
2839   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", (viewUpdated ? "true" : "false"));
2840   return viewUpdated;
2841 }
2842
2843 void Controller::CalculateVerticalOffset(const Size& controlSize)
2844 {
2845   ModelPtr&       model                 = mImpl->mModel;
2846   VisualModelPtr& visualModel           = model->mVisualModel;
2847   Size            layoutSize            = mImpl->mModel->mVisualModel->GetLayoutSize();
2848   Size            oldLayoutSize         = layoutSize;
2849   float           offsetY               = 0.f;
2850   bool            needRecalc            = false;
2851   float           defaultFontLineHeight = mImpl->GetDefaultFontLineHeight();
2852
2853   if(fabsf(layoutSize.height) < Math::MACHINE_EPSILON_1000)
2854   {
2855     // Get the line height of the default font.
2856     layoutSize.height = defaultFontLineHeight;
2857   }
2858
2859   // Whether the text control is editable
2860   const bool isEditable = NULL != mImpl->mEventData;
2861   if(isEditable && layoutSize.height != defaultFontLineHeight)
2862   {
2863     // This code prevents the wrong positioning of cursor when the layout size is bigger/smaller than defaultFontLineHeight.
2864     // This situation occurs when the size of placeholder text is different from the default text.
2865     layoutSize.height = defaultFontLineHeight;
2866     needRecalc        = true;
2867   }
2868
2869   switch(mImpl->mModel->mVerticalAlignment)
2870   {
2871     case VerticalAlignment::TOP:
2872     {
2873       mImpl->mModel->mScrollPosition.y = 0.f;
2874       offsetY                          = 0.f;
2875       break;
2876     }
2877     case VerticalAlignment::CENTER:
2878     {
2879       mImpl->mModel->mScrollPosition.y = floorf(0.5f * (controlSize.height - layoutSize.height)); // try to avoid pixel alignment.
2880       if(needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
2881       break;
2882     }
2883     case VerticalAlignment::BOTTOM:
2884     {
2885       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
2886       if(needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
2887       break;
2888     }
2889   }
2890
2891   if(needRecalc)
2892   {
2893     // Update glyphPositions according to recalculation.
2894     const Length     positionCount  = visualModel->mGlyphPositions.Count();
2895     Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
2896     for(Length index = 0u; index < positionCount; index++)
2897     {
2898       glyphPositions[index].y += offsetY;
2899     }
2900   }
2901 }
2902
2903 // private : Events.
2904
2905 void Controller::ProcessModifyEvents()
2906 {
2907   EventHandler::ProcessModifyEvents(*this);
2908 }
2909
2910 void Controller::TextReplacedEvent()
2911 {
2912   EventHandler::TextReplacedEvent(*this);
2913 }
2914
2915 void Controller::TextInsertedEvent()
2916 {
2917   EventHandler::TextInsertedEvent(*this);
2918 }
2919
2920 void Controller::TextDeletedEvent()
2921 {
2922   EventHandler::TextDeletedEvent(*this);
2923 }
2924
2925 bool Controller::DeleteEvent(int keyCode)
2926 {
2927   return EventHandler::DeleteEvent(*this, keyCode);
2928 }
2929
2930 // private : Helpers.
2931
2932 void Controller::ResetText()
2933 {
2934   // Reset buffers.
2935   mImpl->mModel->mLogicalModel->mText.Clear();
2936
2937   // Reset the embedded images buffer.
2938   mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
2939
2940   // We have cleared everything including the placeholder-text
2941   mImpl->PlaceholderCleared();
2942
2943   mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
2944   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2945   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = 0u;
2946
2947   // Clear any previous text.
2948   mImpl->mTextUpdateInfo.mClearAll = true;
2949
2950   // The natural size needs to be re-calculated.
2951   mImpl->mRecalculateNaturalSize = true;
2952
2953   // The text direction needs to be updated.
2954   mImpl->mUpdateTextDirection = true;
2955
2956   // Apply modifications to the model
2957   mImpl->mOperationsPending = ALL_OPERATIONS;
2958 }
2959
2960 void Controller::ShowPlaceholderText()
2961 {
2962   if(mImpl->IsPlaceholderAvailable())
2963   {
2964     DALI_ASSERT_DEBUG(mImpl->mEventData && "No placeholder text available");
2965
2966     if(NULL == mImpl->mEventData)
2967     {
2968       return;
2969     }
2970
2971     mImpl->mEventData->mIsShowingPlaceholderText = true;
2972
2973     // Disable handles when showing place-holder text
2974     mImpl->mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
2975     mImpl->mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
2976     mImpl->mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
2977
2978     const char* text(NULL);
2979     size_t      size(0);
2980
2981     // TODO - Switch Placeholder text when changing state
2982     if((EventData::INACTIVE != mImpl->mEventData->mState) &&
2983        (0u != mImpl->mEventData->mPlaceholderTextActive.c_str()))
2984     {
2985       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
2986       size = mImpl->mEventData->mPlaceholderTextActive.size();
2987     }
2988     else
2989     {
2990       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
2991       size = mImpl->mEventData->mPlaceholderTextInactive.size();
2992     }
2993
2994     mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
2995     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2996
2997     // Reset model for showing placeholder.
2998     mImpl->mModel->mLogicalModel->mText.Clear();
2999     mImpl->mModel->mVisualModel->SetTextColor(mImpl->mEventData->mPlaceholderTextColor);
3000
3001     // Convert text into UTF-32
3002     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3003     utf32Characters.Resize(size);
3004
3005     // This is a bit horrible but std::string returns a (signed) char*
3006     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
3007
3008     // Transform a text array encoded in utf8 into an array encoded in utf32.
3009     // It returns the actual number of characters.
3010     const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
3011     utf32Characters.Resize(characterCount);
3012
3013     // The characters to be added.
3014     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3015
3016     // Reset the cursor position
3017     mImpl->mEventData->mPrimaryCursorPosition = 0;
3018
3019     // The natural size needs to be re-calculated.
3020     mImpl->mRecalculateNaturalSize = true;
3021
3022     // The text direction needs to be updated.
3023     mImpl->mUpdateTextDirection = true;
3024
3025     // Apply modifications to the model
3026     mImpl->mOperationsPending = ALL_OPERATIONS;
3027
3028     // Update the rest of the model during size negotiation
3029     mImpl->QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
3030   }
3031 }
3032
3033 void Controller::ClearFontData()
3034 {
3035   if(mImpl->mFontDefaults)
3036   {
3037     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3038   }
3039
3040   // Set flags to update the model.
3041   mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
3042   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3043   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
3044
3045   mImpl->mTextUpdateInfo.mClearAll           = true;
3046   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3047   mImpl->mRecalculateNaturalSize             = true;
3048
3049   mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
3050                                                           VALIDATE_FONTS |
3051                                                           SHAPE_TEXT |
3052                                                           BIDI_INFO |
3053                                                           GET_GLYPH_METRICS |
3054                                                           LAYOUT |
3055                                                           UPDATE_LAYOUT_SIZE |
3056                                                           REORDER |
3057                                                           ALIGN);
3058 }
3059
3060 void Controller::ClearStyleData()
3061 {
3062   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3063   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3064 }
3065
3066 void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
3067 {
3068   // Reset the cursor position
3069   if(NULL != mImpl->mEventData)
3070   {
3071     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3072
3073     // Update the cursor if it's in editing mode.
3074     if(EventData::IsEditingState(mImpl->mEventData->mState))
3075     {
3076       mImpl->mEventData->mUpdateCursorPosition = true;
3077     }
3078   }
3079 }
3080
3081 void Controller::ResetScrollPosition()
3082 {
3083   if(NULL != mImpl->mEventData)
3084   {
3085     // Reset the scroll position.
3086     mImpl->mModel->mScrollPosition                = Vector2::ZERO;
3087     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3088   }
3089 }
3090
3091 void Controller::SetControlInterface(ControlInterface* controlInterface)
3092 {
3093   mImpl->mControlInterface = controlInterface;
3094 }
3095
3096 bool Controller::ShouldClearFocusOnEscape() const
3097 {
3098   return mImpl->mShouldClearFocusOnEscape;
3099 }
3100
3101 Actor Controller::CreateBackgroundActor()
3102 {
3103   return mImpl->CreateBackgroundActor();
3104 }
3105
3106 // private : Private contructors & copy operator.
3107
3108 Controller::Controller()
3109 : Controller(nullptr, nullptr, nullptr)
3110 {
3111 }
3112
3113 Controller::Controller(ControlInterface* controlInterface)
3114 : Controller(controlInterface, nullptr, nullptr)
3115 {
3116 }
3117
3118 Controller::Controller(ControlInterface*           controlInterface,
3119                        EditableControlInterface*   editableControlInterface,
3120                        SelectableControlInterface* selectableControlInterface)
3121 : mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface))
3122 {
3123 }
3124
3125 // The copy constructor and operator are left unimplemented.
3126
3127 // protected : Destructor.
3128
3129 Controller::~Controller()
3130 {
3131   delete mImpl;
3132 }
3133
3134 } // namespace Text
3135
3136 } // namespace Toolkit
3137
3138 } // namespace Dali