[AT-SPI] Squashed implementation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
1 /*
2  * Copyright (c) 2020 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-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/rendering/renderer.h>
23 #include <dali/integration-api/debug.h>
24 #include <limits>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/color-segmentation.h>
31 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
32 #include <dali-toolkit/internal/text/multi-language-support.h>
33 #include <dali-toolkit/internal/text/segmentation.h>
34 #include <dali-toolkit/internal/text/shaper.h>
35 #include <dali-toolkit/internal/text/text-control-interface.h>
36 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
37 #include <dali-toolkit/internal/text/text-run-container.h>
38 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
39
40 using namespace Dali;
41
42 namespace
43 {
44
45 /**
46  * @brief Struct used to calculate the selection box.
47  */
48 struct SelectionBoxInfo
49 {
50   float lineOffset;
51   float lineHeight;
52   float minX;
53   float maxX;
54 };
55
56 #if defined(DEBUG_ENABLED)
57 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
58 #endif
59
60 const float MAX_FLOAT = std::numeric_limits<float>::max();
61 const float MIN_FLOAT = std::numeric_limits<float>::min();
62 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
63
64 #define MAKE_SHADER(A)#A
65
66 const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
67 attribute mediump vec2    aPosition;
68 attribute mediump vec4    aColor;
69 varying   mediump vec4    vColor;
70 uniform   highp mat4      uMvpMatrix;
71
72 void main()
73 {
74   mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
75   gl_Position = uMvpMatrix * position;
76   vColor = aColor;
77 }
78 );
79
80 const char* FRAGMENT_SHADER_BACKGROUND = MAKE_SHADER(
81 varying mediump vec4      vColor;
82 uniform lowp    vec4      uColor;
83
84 void main()
85 {
86   gl_FragColor = vColor * uColor;
87 }
88 );
89
90 struct BackgroundVertex
91 {
92   Vector2 mPosition;        ///< Vertex posiiton
93   Vector4 mColor;           ///< Vertex color
94 };
95
96 struct BackgroundMesh
97 {
98   Vector< BackgroundVertex > mVertices;    ///< container of vertices
99   Vector< unsigned short > mIndices;       ///< container of indices
100 };
101
102 const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f );
103 const Dali::Vector4 BACKGROUND_SUB4( 0.58f, 0.87f, 0.96f, 1.f );
104 const Dali::Vector4 BACKGROUND_SUB5( 0.83f, 0.94f, 0.98f, 1.f );
105 const Dali::Vector4 BACKGROUND_SUB6( 1.f, 0.5f, 0.5f, 1.f );
106 const Dali::Vector4 BACKGROUND_SUB7( 1.f, 0.8f, 0.8f, 1.f );
107
108 } // namespace
109
110 namespace Dali
111 {
112
113 namespace Toolkit
114 {
115
116 namespace Text
117 {
118
119 EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
120 : mDecorator( decorator ),
121   mInputMethodContext( inputMethodContext ),
122   mPlaceholderFont( NULL ),
123   mPlaceholderTextActive(),
124   mPlaceholderTextInactive(),
125   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
126   mEventQueue(),
127   mInputStyleChangedQueue(),
128   mPreviousState( INACTIVE ),
129   mState( INACTIVE ),
130   mPrimaryCursorPosition( 0u ),
131   mLeftSelectionPosition( 0u ),
132   mRightSelectionPosition( 0u ),
133   mPreEditStartPosition( 0u ),
134   mPreEditLength( 0u ),
135   mCursorHookPositionX( 0.f ),
136   mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
137   mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
138   mIsShowingPlaceholderText( false ),
139   mPreEditFlag( false ),
140   mDecoratorUpdated( false ),
141   mCursorBlinkEnabled( true ),
142   mGrabHandleEnabled( true ),
143   mGrabHandlePopupEnabled( true ),
144   mSelectionEnabled( true ),
145   mUpdateCursorHookPosition( false ),
146   mUpdateCursorPosition( false ),
147   mUpdateGrabHandlePosition( false ),
148   mUpdateLeftSelectionPosition( false ),
149   mUpdateRightSelectionPosition( false ),
150   mIsLeftHandleSelected( false ),
151   mIsRightHandleSelected( false ),
152   mUpdateHighlightBox( false ),
153   mScrollAfterUpdatePosition( false ),
154   mScrollAfterDelete( false ),
155   mAllTextSelected( false ),
156   mUpdateInputStyle( false ),
157   mPasswordInput( false ),
158   mCheckScrollAmount( false ),
159   mIsPlaceholderPixelSize( false ),
160   mIsPlaceholderElideEnabled( false ),
161   mPlaceholderEllipsisFlag( false ),
162   mShiftSelectionFlag( true ),
163   mUpdateAlignment( false ),
164   mEditingEnabled( true )
165 {
166 }
167
168 EventData::~EventData()
169 {}
170
171 bool Controller::Impl::ProcessInputEvents()
172 {
173   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
174   if( NULL == mEventData )
175   {
176     // Nothing to do if there is no text input.
177     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
178     return false;
179   }
180
181   if( mEventData->mDecorator )
182   {
183     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
184          iter != mEventData->mEventQueue.end();
185          ++iter )
186     {
187       switch( iter->type )
188       {
189         case Event::CURSOR_KEY_EVENT:
190         {
191           OnCursorKeyEvent( *iter );
192           break;
193         }
194         case Event::TAP_EVENT:
195         {
196           OnTapEvent( *iter );
197           break;
198         }
199         case Event::LONG_PRESS_EVENT:
200         {
201           OnLongPressEvent( *iter );
202           break;
203         }
204         case Event::PAN_EVENT:
205         {
206           OnPanEvent( *iter );
207           break;
208         }
209         case Event::GRAB_HANDLE_EVENT:
210         case Event::LEFT_SELECTION_HANDLE_EVENT:
211         case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
212         {
213           OnHandleEvent( *iter );
214           break;
215         }
216         case Event::SELECT:
217         {
218           OnSelectEvent( *iter );
219           break;
220         }
221         case Event::SELECT_ALL:
222         {
223           OnSelectAllEvent();
224           break;
225         }
226         case Event::SELECT_NONE:
227         {
228           OnSelectNoneEvent();
229           break;
230         }
231       }
232     }
233   }
234
235   if( mEventData->mUpdateCursorPosition ||
236       mEventData->mUpdateHighlightBox )
237   {
238     NotifyInputMethodContext();
239   }
240
241   // The cursor must also be repositioned after inserts into the model
242   if( mEventData->mUpdateCursorPosition )
243   {
244     // Updates the cursor position and scrolls the text to make it visible.
245     CursorInfo cursorInfo;
246     // Calculate the cursor position from the new cursor index.
247     GetCursorPosition( mEventData->mPrimaryCursorPosition,
248                        cursorInfo );
249
250     if( NULL != mEditableControlInterface )
251     {
252       mEditableControlInterface->CaretMoved( mEventData->mPrimaryCursorPosition );
253     }
254
255     if( mEventData->mUpdateCursorHookPosition )
256     {
257       // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
258       mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
259       mEventData->mUpdateCursorHookPosition = false;
260     }
261
262     // Scroll first the text after delete ...
263     if( mEventData->mScrollAfterDelete )
264     {
265       ScrollTextToMatchCursor( cursorInfo );
266     }
267
268     // ... then, text can be scrolled to make the cursor visible.
269     if( mEventData->mScrollAfterUpdatePosition )
270     {
271       const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
272       ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
273     }
274     mEventData->mScrollAfterUpdatePosition = false;
275     mEventData->mScrollAfterDelete = false;
276
277     UpdateCursorPosition( cursorInfo );
278
279     mEventData->mDecoratorUpdated = true;
280     mEventData->mUpdateCursorPosition = false;
281     mEventData->mUpdateGrabHandlePosition = false;
282   }
283   else
284   {
285     CursorInfo leftHandleInfo;
286     CursorInfo rightHandleInfo;
287
288     if( mEventData->mUpdateHighlightBox )
289     {
290       GetCursorPosition( mEventData->mLeftSelectionPosition,
291                          leftHandleInfo );
292
293       GetCursorPosition( mEventData->mRightSelectionPosition,
294                          rightHandleInfo );
295
296       if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
297       {
298         if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
299         {
300           CursorInfo& infoLeft = leftHandleInfo;
301
302           const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
303           ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
304
305           CursorInfo& infoRight = rightHandleInfo;
306
307           const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
308           ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
309         }
310         else
311         {
312           CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
313
314           const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
315           ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
316         }
317       }
318     }
319
320     if( mEventData->mUpdateLeftSelectionPosition )
321     {
322       UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
323                              leftHandleInfo );
324
325       SetPopupButtons();
326       mEventData->mDecoratorUpdated = true;
327       mEventData->mUpdateLeftSelectionPosition = false;
328     }
329
330     if( mEventData->mUpdateRightSelectionPosition )
331     {
332       UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
333                              rightHandleInfo );
334
335       SetPopupButtons();
336       mEventData->mDecoratorUpdated = true;
337       mEventData->mUpdateRightSelectionPosition = false;
338     }
339
340     if( mEventData->mUpdateHighlightBox )
341     {
342       RepositionSelectionHandles();
343
344       mEventData->mUpdateLeftSelectionPosition = false;
345       mEventData->mUpdateRightSelectionPosition = false;
346       mEventData->mUpdateHighlightBox = false;
347       mEventData->mIsLeftHandleSelected = false;
348       mEventData->mIsRightHandleSelected = false;
349     }
350
351     mEventData->mScrollAfterUpdatePosition = false;
352   }
353
354   if( mEventData->mUpdateInputStyle )
355   {
356     // Keep a copy of the current input style.
357     InputStyle currentInputStyle;
358     currentInputStyle.Copy( mEventData->mInputStyle );
359
360     // Set the default style first.
361     RetrieveDefaultInputStyle( mEventData->mInputStyle );
362
363     // Get the character index from the cursor index.
364     const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
365
366     // Retrieve the style from the style runs stored in the logical model.
367     mModel->mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
368
369     // Compare if the input style has changed.
370     const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
371
372     if( hasInputStyleChanged )
373     {
374       const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
375       // Queue the input style changed signal.
376       mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
377     }
378
379     mEventData->mUpdateInputStyle = false;
380   }
381
382   mEventData->mEventQueue.clear();
383
384   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
385
386   const bool decoratorUpdated = mEventData->mDecoratorUpdated;
387   mEventData->mDecoratorUpdated = false;
388
389   return decoratorUpdated;
390 }
391
392 void Controller::Impl::NotifyInputMethodContext()
393 {
394   if( mEventData && mEventData->mInputMethodContext )
395   {
396     CharacterIndex cursorPosition = GetLogicalCursorPosition();
397
398     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
399
400     // Update the cursor position by removing the initial white spaces.
401     if( cursorPosition < numberOfWhiteSpaces )
402     {
403       cursorPosition = 0u;
404     }
405     else
406     {
407       cursorPosition -= numberOfWhiteSpaces;
408     }
409
410     mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
411     mEventData->mInputMethodContext.NotifyCursorPosition();
412   }
413 }
414
415 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
416 {
417   if ( mEventData && mEventData->mInputMethodContext )
418   {
419     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
420     mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
421   }
422 }
423
424 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
425 {
426   CharacterIndex cursorPosition = 0u;
427
428   if( mEventData )
429   {
430     if( ( EventData::SELECTING == mEventData->mState ) ||
431         ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
432     {
433       cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
434     }
435     else
436     {
437       cursorPosition = mEventData->mPrimaryCursorPosition;
438     }
439   }
440
441   return cursorPosition;
442 }
443
444 Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
445 {
446   Length numberOfWhiteSpaces = 0u;
447
448   // Get the buffer to the text.
449   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
450
451   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
452   for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
453   {
454     if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
455     {
456       break;
457     }
458   }
459
460   return numberOfWhiteSpaces;
461 }
462
463 void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
464 {
465   // Get the total number of characters.
466   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
467
468   // Retrieve the text.
469   if( 0u != numberOfCharacters )
470   {
471     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
472   }
473 }
474
475 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
476 {
477   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
478   mTextUpdateInfo.mStartGlyphIndex = 0u;
479   mTextUpdateInfo.mStartLineIndex = 0u;
480   numberOfCharacters = 0u;
481
482   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
483   if( 0u == numberOfParagraphs )
484   {
485     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
486     numberOfCharacters = 0u;
487
488     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
489
490     // Nothing else to do if there are no paragraphs.
491     return;
492   }
493
494   // Find the paragraphs to be updated.
495   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
496   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
497   {
498     // Text is being added at the end of the current text.
499     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
500     {
501       // Text is being added in a new paragraph after the last character of the text.
502       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
503       numberOfCharacters = 0u;
504       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
505
506       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
507       mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
508
509       // Nothing else to do;
510       return;
511     }
512
513     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
514   }
515   else
516   {
517     Length numberOfCharactersToUpdate = 0u;
518     if( mTextUpdateInfo.mFullRelayoutNeeded )
519     {
520       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
521     }
522     else
523     {
524       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
525     }
526     mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
527                                            numberOfCharactersToUpdate,
528                                            paragraphsToBeUpdated );
529   }
530
531   if( 0u != paragraphsToBeUpdated.Count() )
532   {
533     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
534     const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
535     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
536
537     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
538     const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
539
540     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
541         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
542         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
543           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
544     {
545       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
546       const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
547
548       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
549     }
550     else
551     {
552       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
553     }
554   }
555
556   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
557   mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
558 }
559
560 void Controller::Impl::ClearFullModelData( OperationsMask operations )
561 {
562   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
563   {
564     mModel->mLogicalModel->mLineBreakInfo.Clear();
565     mModel->mLogicalModel->mParagraphInfo.Clear();
566   }
567
568   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
569   {
570     mModel->mLogicalModel->mScriptRuns.Clear();
571   }
572
573   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
574   {
575     mModel->mLogicalModel->mFontRuns.Clear();
576   }
577
578   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
579   {
580     if( NO_OPERATION != ( BIDI_INFO & operations ) )
581     {
582       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
583       mModel->mLogicalModel->mCharacterDirections.Clear();
584     }
585
586     if( NO_OPERATION != ( REORDER & operations ) )
587     {
588       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
589       for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
590              endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
591            it != endIt;
592            ++it )
593       {
594         BidirectionalLineInfoRun& bidiLineInfo = *it;
595
596         free( bidiLineInfo.visualToLogicalMap );
597         bidiLineInfo.visualToLogicalMap = NULL;
598       }
599       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
600     }
601   }
602
603   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
604   {
605     mModel->mVisualModel->mGlyphs.Clear();
606     mModel->mVisualModel->mGlyphsToCharacters.Clear();
607     mModel->mVisualModel->mCharactersToGlyph.Clear();
608     mModel->mVisualModel->mCharactersPerGlyph.Clear();
609     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
610     mModel->mVisualModel->mGlyphPositions.Clear();
611   }
612
613   if( NO_OPERATION != ( LAYOUT & operations ) )
614   {
615     mModel->mVisualModel->mLines.Clear();
616   }
617
618   if( NO_OPERATION != ( COLOR & operations ) )
619   {
620     mModel->mVisualModel->mColorIndices.Clear();
621     mModel->mVisualModel->mBackgroundColorIndices.Clear();
622   }
623 }
624
625 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
626 {
627   const CharacterIndex endIndexPlusOne = endIndex + 1u;
628
629   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
630   {
631     // Clear the line break info.
632     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
633
634     mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
635                                                  lineBreakInfoBuffer + endIndexPlusOne );
636
637     // Clear the paragraphs.
638     ClearCharacterRuns( startIndex,
639                         endIndex,
640                         mModel->mLogicalModel->mParagraphInfo );
641   }
642
643   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
644   {
645     // Clear the scripts.
646     ClearCharacterRuns( startIndex,
647                         endIndex,
648                         mModel->mLogicalModel->mScriptRuns );
649   }
650
651   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
652   {
653     // Clear the fonts.
654     ClearCharacterRuns( startIndex,
655                         endIndex,
656                         mModel->mLogicalModel->mFontRuns );
657   }
658
659   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
660   {
661     if( NO_OPERATION != ( BIDI_INFO & operations ) )
662     {
663       // Clear the bidirectional paragraph info.
664       ClearCharacterRuns( startIndex,
665                           endIndex,
666                           mModel->mLogicalModel->mBidirectionalParagraphInfo );
667
668       // Clear the character's directions.
669       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
670
671       mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
672                                                          characterDirectionsBuffer + endIndexPlusOne );
673     }
674
675     if( NO_OPERATION != ( REORDER & operations ) )
676     {
677       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
678       uint32_t endRemoveIndex = startRemoveIndex;
679       ClearCharacterRuns( startIndex,
680                           endIndex,
681                           mModel->mLogicalModel->mBidirectionalLineInfo,
682                           startRemoveIndex,
683                           endRemoveIndex );
684
685       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
686
687       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
688       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
689              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
690            it != endIt;
691            ++it )
692       {
693         BidirectionalLineInfoRun& bidiLineInfo = *it;
694
695         free( bidiLineInfo.visualToLogicalMap );
696         bidiLineInfo.visualToLogicalMap = NULL;
697       }
698
699       mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
700                                                            bidirectionalLineInfoBuffer + endRemoveIndex );
701     }
702   }
703 }
704
705 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
706 {
707   const CharacterIndex endIndexPlusOne = endIndex + 1u;
708   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
709
710   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
711   GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
712   Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
713
714   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
715   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
716
717   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
718   {
719     // Update the character to glyph indices.
720     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
721            endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
722          it != endIt;
723          ++it )
724     {
725       CharacterIndex& index = *it;
726       index -= numberOfGlyphsRemoved;
727     }
728
729     // Clear the character to glyph conversion table.
730     mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
731                                                     charactersToGlyphBuffer + endIndexPlusOne );
732
733     // Clear the glyphs per character table.
734     mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
735                                                      glyphsPerCharacterBuffer + endIndexPlusOne );
736
737     // Clear the glyphs buffer.
738     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
739     mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
740                                          glyphsBuffer + endGlyphIndexPlusOne );
741
742     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
743
744     // Update the glyph to character indices.
745     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
746            endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
747          it != endIt;
748          ++it )
749     {
750       CharacterIndex& index = *it;
751       index -= numberOfCharactersRemoved;
752     }
753
754     // Clear the glyphs to characters buffer.
755     mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
756                                                      glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
757
758     // Clear the characters per glyph buffer.
759     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
760     mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
761                                                      charactersPerGlyphBuffer + endGlyphIndexPlusOne );
762
763     // Clear the positions buffer.
764     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
765     mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
766                                                  positionsBuffer + endGlyphIndexPlusOne );
767   }
768
769   if( NO_OPERATION != ( LAYOUT & operations ) )
770   {
771     // Clear the lines.
772     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
773     uint32_t endRemoveIndex = startRemoveIndex;
774     ClearCharacterRuns( startIndex,
775                         endIndex,
776                         mModel->mVisualModel->mLines,
777                         startRemoveIndex,
778                         endRemoveIndex );
779
780     // Will update the glyph runs.
781     startRemoveIndex = mModel->mVisualModel->mLines.Count();
782     endRemoveIndex = startRemoveIndex;
783     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
784                     endGlyphIndexPlusOne - 1u,
785                     mModel->mVisualModel->mLines,
786                     startRemoveIndex,
787                     endRemoveIndex );
788
789     // Set the line index from where to insert the new laid-out lines.
790     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
791
792     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
793     mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
794                                         linesBuffer + endRemoveIndex );
795   }
796
797   if( NO_OPERATION != ( COLOR & operations ) )
798   {
799     if( 0u != mModel->mVisualModel->mColorIndices.Count() )
800     {
801       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
802       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
803                                                  colorIndexBuffer + endGlyphIndexPlusOne );
804     }
805
806     if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
807     {
808       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
809       mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
810                                                            backgroundColorIndexBuffer + endGlyphIndexPlusOne );
811     }
812   }
813 }
814
815 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
816 {
817   if( mTextUpdateInfo.mClearAll ||
818       ( ( 0u == startIndex ) &&
819         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
820   {
821     ClearFullModelData( operations );
822   }
823   else
824   {
825     // Clear the model data related with characters.
826     ClearCharacterModelData( startIndex, endIndex, operations );
827
828     // Clear the model data related with glyphs.
829     ClearGlyphModelData( startIndex, endIndex, operations );
830   }
831
832   // The estimated number of lines. Used to avoid reallocations when layouting.
833   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
834
835   mModel->mVisualModel->ClearCaches();
836 }
837
838 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
839 {
840   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
841
842   // Calculate the operations to be done.
843   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
844
845   if( NO_OPERATION == operations )
846   {
847     // Nothing to do if no operations are pending and required.
848     return false;
849   }
850
851   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
852   Vector<Character> displayCharacters;
853   bool useHiddenText = false;
854   if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
855   {
856     mHiddenInput->Substitute( srcCharacters,displayCharacters );
857     useHiddenText = true;
858   }
859
860   Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
861   const Length numberOfCharacters = utf32Characters.Count();
862
863   // Index to the first character of the first paragraph to be updated.
864   CharacterIndex startIndex = 0u;
865   // Number of characters of the paragraphs to be removed.
866   Length paragraphCharacters = 0u;
867
868   CalculateTextUpdateIndices( paragraphCharacters );
869
870   // Check whether the indices for updating the text is valid
871   if ( numberOfCharacters > 0u &&
872        ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
873          mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
874   {
875     std::string currentText;
876     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
877
878     DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
879     DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
880
881     // Dump mTextUpdateInfo
882     DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
883     DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
884     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
885     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
886     DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
887     DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
888     DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
889     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
890     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
891     DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
892     DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
893     DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
894     DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
895
896     return false;
897   }
898
899   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
900
901   if( mTextUpdateInfo.mClearAll ||
902       ( 0u != paragraphCharacters ) )
903   {
904     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
905   }
906
907   mTextUpdateInfo.mClearAll = false;
908
909   // Whether the model is updated.
910   bool updated = false;
911
912   Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
913   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
914
915   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
916   {
917     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
918     // calculate the bidirectional info for each 'paragraph'.
919     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
920     // is not shaped together).
921     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
922
923     SetLineBreakInfo( utf32Characters,
924                       startIndex,
925                       requestedNumberOfCharacters,
926                       lineBreakInfo );
927
928     // Create the paragraph info.
929     mModel->mLogicalModel->CreateParagraphInfo( startIndex,
930                                                 requestedNumberOfCharacters );
931     updated = true;
932   }
933
934   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
935   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
936
937   Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
938   Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
939
940   if( getScripts || validateFonts )
941   {
942     // Validates the fonts assigned by the application or assigns default ones.
943     // It makes sure all the characters are going to be rendered by the correct font.
944     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
945
946     if( getScripts )
947     {
948       // Retrieves the scripts used in the text.
949       multilanguageSupport.SetScripts( utf32Characters,
950                                        startIndex,
951                                        requestedNumberOfCharacters,
952                                        scripts );
953     }
954
955     if( validateFonts )
956     {
957       // Validate the fonts set through the mark-up string.
958       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
959
960       // Get the default font's description.
961       TextAbstraction::FontDescription defaultFontDescription;
962       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
963
964       if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
965       {
966         // If the placeholder font is set specifically, only placeholder font is changed.
967         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
968         if( mEventData->mPlaceholderFont->sizeDefined )
969         {
970           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
971         }
972       }
973       else if( NULL != mFontDefaults )
974       {
975         // Set the normal font and the placeholder font.
976         defaultFontDescription = mFontDefaults->mFontDescription;
977
978         if( mTextFitEnabled )
979         {
980           defaultPointSize = mFontDefaults->mFitPointSize * 64u;
981         }
982         else
983         {
984           defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
985         }
986       }
987
988       // Validates the fonts. If there is a character with no assigned font it sets a default one.
989       // After this call, fonts are validated.
990       multilanguageSupport.ValidateFonts( utf32Characters,
991                                           scripts,
992                                           fontDescriptionRuns,
993                                           defaultFontDescription,
994                                           defaultPointSize,
995                                           startIndex,
996                                           requestedNumberOfCharacters,
997                                           validFonts );
998     }
999     updated = true;
1000   }
1001
1002   Vector<Character> mirroredUtf32Characters;
1003   bool textMirrored = false;
1004   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
1005   if( NO_OPERATION != ( BIDI_INFO & operations ) )
1006   {
1007     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
1008     bidirectionalInfo.Reserve( numberOfParagraphs );
1009
1010     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1011     SetBidirectionalInfo( utf32Characters,
1012                           scripts,
1013                           lineBreakInfo,
1014                           startIndex,
1015                           requestedNumberOfCharacters,
1016                           bidirectionalInfo,
1017                           mModel->mMatchSystemLanguageDirection,
1018                           mLayoutDirection );
1019
1020     if( 0u != bidirectionalInfo.Count() )
1021     {
1022       // Only set the character directions if there is right to left characters.
1023       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
1024       GetCharactersDirection( bidirectionalInfo,
1025                               numberOfCharacters,
1026                               startIndex,
1027                               requestedNumberOfCharacters,
1028                               directions );
1029
1030       // This paragraph has right to left text. Some characters may need to be mirrored.
1031       // TODO: consider if the mirrored string can be stored as well.
1032
1033       textMirrored = GetMirroredText( utf32Characters,
1034                                       directions,
1035                                       bidirectionalInfo,
1036                                       startIndex,
1037                                       requestedNumberOfCharacters,
1038                                       mirroredUtf32Characters );
1039     }
1040     else
1041     {
1042       // There is no right to left characters. Clear the directions vector.
1043       mModel->mLogicalModel->mCharacterDirections.Clear();
1044     }
1045     updated = true;
1046   }
1047
1048   Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
1049   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
1050   Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
1051   Vector<GlyphIndex> newParagraphGlyphs;
1052   newParagraphGlyphs.Reserve( numberOfParagraphs );
1053
1054   const Length currentNumberOfGlyphs = glyphs.Count();
1055   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
1056   {
1057     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1058     // Shapes the text.
1059     ShapeText( textToShape,
1060                lineBreakInfo,
1061                scripts,
1062                validFonts,
1063                startIndex,
1064                mTextUpdateInfo.mStartGlyphIndex,
1065                requestedNumberOfCharacters,
1066                glyphs,
1067                glyphsToCharactersMap,
1068                charactersPerGlyph,
1069                newParagraphGlyphs );
1070
1071     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
1072     mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1073     mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1074     updated = true;
1075   }
1076
1077   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
1078
1079   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
1080   {
1081     GlyphInfo* glyphsBuffer = glyphs.Begin();
1082     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
1083
1084     // Update the width and advance of all new paragraph characters.
1085     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
1086     {
1087       const GlyphIndex index = *it;
1088       GlyphInfo& glyph = *( glyphsBuffer + index );
1089
1090       glyph.xBearing = 0.f;
1091       glyph.width = 0.f;
1092       glyph.advance = 0.f;
1093     }
1094     updated = true;
1095   }
1096
1097   if( ( NULL != mEventData ) &&
1098       mEventData->mPreEditFlag &&
1099       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
1100   {
1101     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
1102     mEventData->mInputMethodContext.GetPreeditStyle( attrs );
1103     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
1104
1105     // Check the type of preedit and run it.
1106     for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
1107     {
1108       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
1109       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex  );
1110       type = attrData.preeditType;
1111
1112       // Check the number of commit characters for the start position.
1113       unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
1114       Length numberOfIndices = attrData.endIndex - attrData.startIndex;
1115
1116       switch( type )
1117       {
1118         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
1119         {
1120           // Add the underline for the pre-edit text.
1121           GlyphRun underlineRun;
1122           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1123           underlineRun.numberOfGlyphs = numberOfIndices;
1124           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1125           break;
1126         }
1127         case Dali::InputMethodContext::PreeditStyle::REVERSE:
1128         {
1129           Vector4 textColor = mModel->mVisualModel->GetTextColor();
1130           ColorRun backgroundColorRun;
1131           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1132           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1133           backgroundColorRun.color = textColor;
1134           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1135
1136           Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
1137           Vector<ColorRun>  colorRuns;
1138           colorRuns.Resize( 1u );
1139           ColorRun& colorRun = *( colorRuns.Begin() );
1140           colorRun.color = backgroundColor;
1141           colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1142           colorRun.characterRun.numberOfCharacters = numberOfIndices;
1143
1144           mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
1145           break;
1146         }
1147         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
1148         {
1149           ColorRun backgroundColorRun;
1150           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1151           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1152           backgroundColorRun.color = LIGHT_BLUE;
1153           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1154           break;
1155         }
1156         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
1157         {
1158           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
1159           ColorRun backgroundColorRun;
1160           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1161           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1162           backgroundColorRun.color = BACKGROUND_SUB4;
1163           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1164
1165           GlyphRun underlineRun;
1166           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1167           underlineRun.numberOfGlyphs = numberOfIndices;
1168           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1169           break;
1170         }
1171         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
1172         {
1173           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
1174           ColorRun backgroundColorRun;
1175           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1176           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1177           backgroundColorRun.color = BACKGROUND_SUB5;
1178           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1179
1180           GlyphRun underlineRun;
1181           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1182           underlineRun.numberOfGlyphs = numberOfIndices;
1183           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1184           break;
1185         }
1186         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
1187         {
1188           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
1189           ColorRun backgroundColorRun;
1190           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1191           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1192           backgroundColorRun.color = BACKGROUND_SUB6;
1193           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1194
1195           GlyphRun underlineRun;
1196           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1197           underlineRun.numberOfGlyphs = numberOfIndices;
1198           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1199           break;
1200         }
1201         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
1202         {
1203           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
1204           ColorRun backgroundColorRun;
1205           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1206           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1207           backgroundColorRun.color = BACKGROUND_SUB7;
1208           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1209
1210           GlyphRun underlineRun;
1211           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1212           underlineRun.numberOfGlyphs = numberOfIndices;
1213           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1214           break;
1215         }
1216         case Dali::InputMethodContext::PreeditStyle::NONE:
1217         default:
1218         {
1219           break;
1220         }
1221       }
1222     }
1223     attrs.Clear();
1224     updated = true;
1225   }
1226
1227   if( NO_OPERATION != ( COLOR & operations ) )
1228   {
1229     // Set the color runs in glyphs.
1230     SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
1231                               mModel->mVisualModel->mCharactersToGlyph,
1232                               mModel->mVisualModel->mGlyphsPerCharacter,
1233                               startIndex,
1234                               mTextUpdateInfo.mStartGlyphIndex,
1235                               requestedNumberOfCharacters,
1236                               mModel->mVisualModel->mColors,
1237                               mModel->mVisualModel->mColorIndices );
1238
1239     // Set the background color runs in glyphs.
1240     SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
1241                               mModel->mVisualModel->mCharactersToGlyph,
1242                               mModel->mVisualModel->mGlyphsPerCharacter,
1243                               startIndex,
1244                               mTextUpdateInfo.mStartGlyphIndex,
1245                               requestedNumberOfCharacters,
1246                               mModel->mVisualModel->mBackgroundColors,
1247                               mModel->mVisualModel->mBackgroundColorIndices );
1248
1249     updated = true;
1250   }
1251
1252
1253   // The estimated number of lines. Used to avoid reallocations when layouting.
1254   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
1255
1256   // Set the previous number of characters for the next time the text is updated.
1257   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1258
1259   return updated;
1260 }
1261
1262 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
1263 {
1264   // Sets the default text's color.
1265   inputStyle.textColor = mTextColor;
1266   inputStyle.isDefaultColor = true;
1267
1268   inputStyle.familyName.clear();
1269   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1270   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
1271   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
1272   inputStyle.size = 0.f;
1273
1274   inputStyle.lineSpacing = 0.f;
1275
1276   inputStyle.underlineProperties.clear();
1277   inputStyle.shadowProperties.clear();
1278   inputStyle.embossProperties.clear();
1279   inputStyle.outlineProperties.clear();
1280
1281   inputStyle.isFamilyDefined = false;
1282   inputStyle.isWeightDefined = false;
1283   inputStyle.isWidthDefined = false;
1284   inputStyle.isSlantDefined = false;
1285   inputStyle.isSizeDefined = false;
1286
1287   inputStyle.isLineSpacingDefined = false;
1288
1289   inputStyle.isUnderlineDefined = false;
1290   inputStyle.isShadowDefined = false;
1291   inputStyle.isEmbossDefined = false;
1292   inputStyle.isOutlineDefined = false;
1293
1294   // Sets the default font's family name, weight, width, slant and size.
1295   if( mFontDefaults )
1296   {
1297     if( mFontDefaults->familyDefined )
1298     {
1299       inputStyle.familyName = mFontDefaults->mFontDescription.family;
1300       inputStyle.isFamilyDefined = true;
1301     }
1302
1303     if( mFontDefaults->weightDefined )
1304     {
1305       inputStyle.weight = mFontDefaults->mFontDescription.weight;
1306       inputStyle.isWeightDefined = true;
1307     }
1308
1309     if( mFontDefaults->widthDefined )
1310     {
1311       inputStyle.width = mFontDefaults->mFontDescription.width;
1312       inputStyle.isWidthDefined = true;
1313     }
1314
1315     if( mFontDefaults->slantDefined )
1316     {
1317       inputStyle.slant = mFontDefaults->mFontDescription.slant;
1318       inputStyle.isSlantDefined = true;
1319     }
1320
1321     if( mFontDefaults->sizeDefined )
1322     {
1323       inputStyle.size = mFontDefaults->mDefaultPointSize;
1324       inputStyle.isSizeDefined = true;
1325     }
1326   }
1327 }
1328
1329 float Controller::Impl::GetDefaultFontLineHeight()
1330 {
1331   FontId defaultFontId = 0u;
1332   if( NULL == mFontDefaults )
1333   {
1334     TextAbstraction::FontDescription fontDescription;
1335     defaultFontId = mFontClient.GetFontId( fontDescription );
1336   }
1337   else
1338   {
1339     defaultFontId = mFontDefaults->GetFontId( mFontClient );
1340   }
1341
1342   Text::FontMetrics fontMetrics;
1343   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
1344
1345   return( fontMetrics.ascender - fontMetrics.descender );
1346 }
1347
1348 void Controller::Impl::OnCursorKeyEvent( const Event& event )
1349 {
1350   ControllerImplEventHandler::OnCursorKeyEvent(*this, event);
1351 }
1352
1353 void Controller::Impl::OnTapEvent( const Event& event )
1354 {
1355   ControllerImplEventHandler::OnTapEvent(*this, event);
1356 }
1357
1358 void Controller::Impl::OnPanEvent( const Event& event )
1359 {
1360   ControllerImplEventHandler::OnPanEvent(*this, event);
1361 }
1362
1363 void Controller::Impl::OnLongPressEvent( const Event& event )
1364 {
1365   ControllerImplEventHandler::OnLongPressEvent(*this, event);
1366 }
1367
1368 void Controller::Impl::OnHandleEvent( const Event& event )
1369 {
1370   ControllerImplEventHandler::OnHandleEvent(*this, event);
1371 }
1372
1373 void Controller::Impl::OnSelectEvent( const Event& event )
1374 {
1375   ControllerImplEventHandler::OnSelectEvent(*this, event);
1376 }
1377
1378 void Controller::Impl::OnSelectAllEvent()
1379 {
1380   ControllerImplEventHandler::OnSelectAllEvent(*this);
1381 }
1382
1383 void Controller::Impl::OnSelectNoneEvent()
1384 {
1385   ControllerImplEventHandler::OnSelectNoneEvent(*this);
1386 }
1387
1388 void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint32_t *pEnd)
1389 {
1390   if( nullptr == mEventData )
1391   {
1392     // Nothing to do if there is no text.
1393     return;
1394   }
1395
1396   if( mEventData->mSelectionEnabled && (pStart || pEnd))
1397   {
1398     uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1399
1400     if (pStart)
1401     {
1402       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
1403     }
1404     if (pEnd)
1405     {
1406       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
1407     }
1408
1409     if (mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1410     {
1411       ChangeState( EventData::EDITING );
1412       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
1413       mEventData->mUpdateCursorPosition = true;
1414     }
1415     else
1416     {
1417       ChangeState( EventData::SELECTING );
1418       mEventData->mUpdateHighlightBox = true;
1419       mEventData->mUpdateLeftSelectionPosition = true;
1420       mEventData->mUpdateRightSelectionPosition = true;
1421     }
1422   }
1423 }
1424
1425 Uint32Pair Controller::Impl::GetTextSelectionRange() const
1426 {
1427   Uint32Pair range;
1428
1429   if( mEventData )
1430   {
1431     range.first = mEventData->mLeftSelectionPosition;
1432     range.second = mEventData->mRightSelectionPosition;
1433   }
1434
1435   return range;
1436 }
1437
1438 bool Controller::Impl::IsEditable() const
1439 {
1440   return mEventData && mEventData->mEditingEnabled;
1441 }
1442
1443 void Controller::Impl::SetEditable( bool editable )
1444 {
1445   if( mEventData)
1446   {
1447     mEventData->mEditingEnabled = editable;
1448   }
1449 }
1450
1451 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
1452 {
1453   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
1454   {
1455     // Nothing to select if handles are in the same place.
1456     selectedText.clear();
1457     return;
1458   }
1459
1460   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1461
1462   //Get start and end position of selection
1463   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1464   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
1465
1466   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
1467   const Length numberOfCharacters = utf32Characters.Count();
1468
1469   // Validate the start and end selection points
1470   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
1471   {
1472     //Get text as a UTF8 string
1473     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
1474
1475     if( deleteAfterRetrieval ) // Only delete text if copied successfully
1476     {
1477       // Keep a copy of the current input style.
1478       InputStyle currentInputStyle;
1479       currentInputStyle.Copy( mEventData->mInputStyle );
1480
1481       // Set as input style the style of the first deleted character.
1482       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
1483
1484       // Compare if the input style has changed.
1485       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
1486
1487       if( hasInputStyleChanged )
1488       {
1489         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
1490         // Queue the input style changed signal.
1491         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
1492       }
1493
1494       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
1495
1496       // Mark the paragraphs to be updated.
1497       if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
1498       {
1499         mTextUpdateInfo.mCharacterIndex = 0;
1500         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1501         mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
1502         mTextUpdateInfo.mClearAll = true;
1503       }
1504       else
1505       {
1506         mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1507         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1508       }
1509
1510       // Delete text between handles
1511       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1512       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1513       utf32Characters.Erase( first, last );
1514
1515       // Will show the cursor at the first character of the selection.
1516       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1517     }
1518     else
1519     {
1520       // Will show the cursor at the last character of the selection.
1521       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1522     }
1523
1524     mEventData->mDecoratorUpdated = true;
1525   }
1526 }
1527
1528 void Controller::Impl::SetSelection( int start, int end )
1529 {
1530   mEventData->mLeftSelectionPosition = start;
1531   mEventData->mRightSelectionPosition = end;
1532   mEventData->mUpdateCursorPosition = true;
1533 }
1534
1535 std::pair< int, int > Controller::Impl::GetSelectionIndexes() const
1536 {
1537   return { mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition };
1538 }
1539
1540 void Controller::Impl::ShowClipboard()
1541 {
1542   if( mClipboard )
1543   {
1544     mClipboard.ShowClipboard();
1545   }
1546 }
1547
1548 void Controller::Impl::HideClipboard()
1549 {
1550   if( mClipboard && mClipboardHideEnabled )
1551   {
1552     mClipboard.HideClipboard();
1553   }
1554 }
1555
1556 void Controller::Impl::SetClipboardHideEnable(bool enable)
1557 {
1558   mClipboardHideEnabled = enable;
1559 }
1560
1561 bool Controller::Impl::CopyStringToClipboard( const std::string& source )
1562 {
1563   //Send string to clipboard
1564   return ( mClipboard && mClipboard.SetItem( source ) );
1565 }
1566
1567 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
1568 {
1569   std::string selectedText;
1570   RetrieveSelection( selectedText, deleteAfterSending );
1571   CopyStringToClipboard( selectedText );
1572   ChangeState( EventData::EDITING );
1573 }
1574
1575 void Controller::Impl::RequestGetTextFromClipboard()
1576 {
1577   if ( mClipboard )
1578   {
1579     mClipboard.RequestItem();
1580   }
1581 }
1582
1583 void Controller::Impl::RepositionSelectionHandles()
1584 {
1585   CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
1586   CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
1587
1588   if( selectionStart == selectionEnd )
1589   {
1590     // Nothing to select if handles are in the same place.
1591     // So, deactive Highlight box.
1592     mEventData->mDecorator->SetHighlightActive( false );
1593     return;
1594   }
1595
1596   mEventData->mDecorator->ClearHighlights();
1597
1598   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
1599   const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
1600   const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
1601   const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
1602   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1603   const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
1604   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
1605
1606   const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
1607   const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
1608   const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
1609
1610   // Swap the indices if the start is greater than the end.
1611   const bool indicesSwapped = selectionStart > selectionEnd;
1612
1613   // Tell the decorator to flip the selection handles if needed.
1614   mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
1615
1616   if( indicesSwapped )
1617   {
1618     std::swap( selectionStart, selectionEnd );
1619   }
1620
1621   // Get the indices to the first and last selected glyphs.
1622   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
1623   const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
1624   const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
1625   const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
1626
1627   // Get the lines where the glyphs are laid-out.
1628   const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
1629
1630   LineIndex lineIndex = 0u;
1631   Length numberOfLines = 0u;
1632   mModel->mVisualModel->GetNumberOfLines( glyphStart,
1633                                           1u + glyphEnd - glyphStart,
1634                                           lineIndex,
1635                                           numberOfLines );
1636   const LineIndex firstLineIndex = lineIndex;
1637
1638   // Create the structure to store some selection box info.
1639   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
1640   selectionBoxLinesInfo.Resize( numberOfLines );
1641
1642   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
1643   selectionBoxInfo->minX = MAX_FLOAT;
1644   selectionBoxInfo->maxX = MIN_FLOAT;
1645
1646   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
1647   float minHighlightX = std::numeric_limits<float>::max();
1648   float maxHighlightX = std::numeric_limits<float>::min();
1649   Size highLightSize;
1650   Vector2 highLightPosition; // The highlight position in decorator's coords.
1651
1652   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
1653
1654   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
1655   selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
1656                                                       firstLineIndex );
1657
1658   // Transform to decorator's (control) coords.
1659   selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
1660
1661   lineRun += firstLineIndex;
1662
1663   // The line height is the addition of the line ascender and the line descender.
1664   // However, the line descender has a negative value, hence the subtraction.
1665   selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
1666
1667   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
1668
1669   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
1670   const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
1671   bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionStart ) );
1672
1673   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
1674   const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
1675   bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
1676
1677   // The number of quads of the selection box.
1678   const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
1679   mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
1680
1681   // Count the actual number of quads.
1682   unsigned int actualNumberOfQuads = 0u;
1683   Vector4 quad;
1684
1685   // Traverse the glyphs.
1686   for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
1687   {
1688     const GlyphInfo& glyph = *( glyphsBuffer + index );
1689     const Vector2& position = *( positionsBuffer + index );
1690
1691     if( splitStartGlyph )
1692     {
1693       // If the first glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
1694
1695       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
1696       const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
1697       // Get the direction of the character.
1698       CharacterDirection isCurrentRightToLeft = false;
1699       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
1700       {
1701         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
1702       }
1703
1704       // The end point could be in the middle of the ligature.
1705       // Calculate the number of characters selected.
1706       const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
1707
1708       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
1709       quad.y = selectionBoxInfo->lineOffset;
1710       quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
1711       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
1712
1713       // Store the min and max 'x' for each line.
1714       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
1715       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
1716
1717       mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
1718       ++actualNumberOfQuads;
1719
1720       splitStartGlyph = false;
1721       continue;
1722     }
1723
1724     if( splitEndGlyph && ( index == glyphEnd ) )
1725     {
1726       // Equally, if the last glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
1727
1728       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
1729       const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
1730       // Get the direction of the character.
1731       CharacterDirection isCurrentRightToLeft = false;
1732       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
1733       {
1734         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
1735       }
1736
1737       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
1738
1739       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
1740       quad.y = selectionBoxInfo->lineOffset;
1741       quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
1742       quad.w = quad.y + selectionBoxInfo->lineHeight;
1743
1744       // Store the min and max 'x' for each line.
1745       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
1746       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
1747
1748       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1749                                             quad );
1750       ++actualNumberOfQuads;
1751
1752       splitEndGlyph = false;
1753       continue;
1754     }
1755
1756     quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
1757     quad.y = selectionBoxInfo->lineOffset;
1758     quad.z = quad.x + glyph.advance;
1759     quad.w = quad.y + selectionBoxInfo->lineHeight;
1760
1761     // Store the min and max 'x' for each line.
1762     selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
1763     selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
1764
1765     mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1766                                           quad );
1767     ++actualNumberOfQuads;
1768
1769     // Whether to retrieve the next line.
1770     if( index == lastGlyphOfLine )
1771     {
1772       ++lineIndex;
1773       if( lineIndex < firstLineIndex + numberOfLines )
1774       {
1775         // Retrieve the next line.
1776         ++lineRun;
1777
1778         // Get the last glyph of the new line.
1779         lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
1780
1781         // Keep the offset and height of the current selection box.
1782         const float currentLineOffset = selectionBoxInfo->lineOffset;
1783         const float currentLineHeight = selectionBoxInfo->lineHeight;
1784
1785         // Get the selection box info for the next line.
1786         ++selectionBoxInfo;
1787
1788         selectionBoxInfo->minX = MAX_FLOAT;
1789         selectionBoxInfo->maxX = MIN_FLOAT;
1790
1791         // Update the line's vertical offset.
1792         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
1793
1794         // The line height is the addition of the line ascender and the line descender.
1795         // However, the line descender has a negative value, hence the subtraction.
1796         selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
1797       }
1798     }
1799   }
1800
1801   // Traverses all the lines and updates the min and max 'x' positions and the total height.
1802   // The final width is calculated after 'boxifying' the selection.
1803   for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
1804          endIt = selectionBoxLinesInfo.End();
1805        it != endIt;
1806        ++it )
1807   {
1808     const SelectionBoxInfo& info = *it;
1809
1810     // Update the size of the highlighted text.
1811     highLightSize.height += info.lineHeight;
1812     minHighlightX = std::min( minHighlightX, info.minX );
1813     maxHighlightX = std::max( maxHighlightX, info.maxX );
1814   }
1815
1816   // Add extra geometry to 'boxify' the selection.
1817
1818   if( 1u < numberOfLines )
1819   {
1820     // Boxify the first line.
1821     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
1822     const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
1823
1824     bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
1825     bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
1826
1827     if( boxifyBegin )
1828     {
1829       quad.x = 0.f;
1830       quad.y = firstSelectionBoxLineInfo.lineOffset;
1831       quad.z = firstSelectionBoxLineInfo.minX;
1832       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
1833
1834       // Boxify at the beginning of the line.
1835       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1836                                             quad );
1837       ++actualNumberOfQuads;
1838
1839       // Update the size of the highlighted text.
1840       minHighlightX = 0.f;
1841     }
1842
1843     if( boxifyEnd )
1844     {
1845       quad.x = firstSelectionBoxLineInfo.maxX;
1846       quad.y = firstSelectionBoxLineInfo.lineOffset;
1847       quad.z = mModel->mVisualModel->mControlSize.width;
1848       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
1849
1850       // Boxify at the end of the line.
1851       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1852                                             quad );
1853       ++actualNumberOfQuads;
1854
1855       // Update the size of the highlighted text.
1856       maxHighlightX = mModel->mVisualModel->mControlSize.width;
1857     }
1858
1859     // Boxify the central lines.
1860     if( 2u < numberOfLines )
1861     {
1862       for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
1863              endIt = selectionBoxLinesInfo.End() - 1u;
1864            it != endIt;
1865            ++it )
1866       {
1867         const SelectionBoxInfo& info = *it;
1868
1869         quad.x = 0.f;
1870         quad.y = info.lineOffset;
1871         quad.z = info.minX;
1872         quad.w = info.lineOffset + info.lineHeight;
1873
1874         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1875                                               quad );
1876         ++actualNumberOfQuads;
1877
1878         quad.x = info.maxX;
1879         quad.y = info.lineOffset;
1880         quad.z = mModel->mVisualModel->mControlSize.width;
1881         quad.w = info.lineOffset + info.lineHeight;
1882
1883         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1884                                               quad );
1885         ++actualNumberOfQuads;
1886       }
1887
1888       // Update the size of the highlighted text.
1889       minHighlightX = 0.f;
1890       maxHighlightX = mModel->mVisualModel->mControlSize.width;
1891     }
1892
1893     // Boxify the last line.
1894     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
1895     const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
1896
1897     boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
1898     boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
1899
1900     if( boxifyBegin )
1901     {
1902       quad.x = 0.f;
1903       quad.y = lastSelectionBoxLineInfo.lineOffset;
1904       quad.z = lastSelectionBoxLineInfo.minX;
1905       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
1906
1907       // Boxify at the beginning of the line.
1908       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1909                                             quad );
1910       ++actualNumberOfQuads;
1911
1912       // Update the size of the highlighted text.
1913       minHighlightX = 0.f;
1914     }
1915
1916     if( boxifyEnd )
1917     {
1918       quad.x = lastSelectionBoxLineInfo.maxX;
1919       quad.y = lastSelectionBoxLineInfo.lineOffset;
1920       quad.z = mModel->mVisualModel->mControlSize.width;
1921       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
1922
1923       // Boxify at the end of the line.
1924       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1925                                             quad );
1926       ++actualNumberOfQuads;
1927
1928       // Update the size of the highlighted text.
1929       maxHighlightX = mModel->mVisualModel->mControlSize.width;
1930     }
1931   }
1932
1933   // Set the actual number of quads.
1934   mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
1935
1936   // Sets the highlight's size and position. In decorator's coords.
1937   // The highlight's height has been calculated above (before 'boxifying' the highlight).
1938   highLightSize.width = maxHighlightX - minHighlightX;
1939
1940   highLightPosition.x = minHighlightX;
1941   const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
1942   highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
1943
1944   mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
1945
1946   if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
1947   {
1948     CursorInfo primaryCursorInfo;
1949     GetCursorPosition( mEventData->mLeftSelectionPosition,
1950                        primaryCursorInfo );
1951
1952     const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
1953
1954     mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
1955                                          primaryPosition.x,
1956                                          primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
1957                                          primaryCursorInfo.lineHeight );
1958
1959     CursorInfo secondaryCursorInfo;
1960     GetCursorPosition( mEventData->mRightSelectionPosition,
1961                        secondaryCursorInfo );
1962
1963     const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
1964
1965     mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
1966                                          secondaryPosition.x,
1967                                          secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
1968                                          secondaryCursorInfo.lineHeight );
1969   }
1970
1971   // Set the flag to update the decorator.
1972   mEventData->mDecoratorUpdated = true;
1973 }
1974
1975 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
1976 {
1977   if( NULL == mEventData )
1978   {
1979     // Nothing to do if there is no text input.
1980     return;
1981   }
1982
1983   if( IsShowingPlaceholderText() )
1984   {
1985     // Nothing to do if there is the place-holder text.
1986     return;
1987   }
1988
1989   const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
1990   const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
1991   if( ( 0 == numberOfGlyphs ) ||
1992       ( 0 == numberOfLines ) )
1993   {
1994     // Nothing to do if there is no text.
1995     return;
1996   }
1997
1998   // Find which word was selected
1999   CharacterIndex selectionStart( 0 );
2000   CharacterIndex selectionEnd( 0 );
2001   CharacterIndex noTextHitIndex( 0 );
2002   const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
2003                                                   mModel->mLogicalModel,
2004                                                   mMetrics,
2005                                                   visualX,
2006                                                   visualY,
2007                                                   selectionStart,
2008                                                   selectionEnd,
2009                                                   noTextHitIndex );
2010   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
2011
2012   if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
2013   {
2014     ChangeState( EventData::SELECTING );
2015
2016     mEventData->mLeftSelectionPosition = selectionStart;
2017     mEventData->mRightSelectionPosition = selectionEnd;
2018
2019     mEventData->mUpdateLeftSelectionPosition = true;
2020     mEventData->mUpdateRightSelectionPosition = true;
2021     mEventData->mUpdateHighlightBox = true;
2022
2023     // It may happen an InputMethodContext commit event arrives before the selection event
2024     // if the InputMethodContext is in pre-edit state. The commit event will set the
2025     // mEventData->mUpdateCursorPosition flag to true. If it's not set back
2026     // to false, the highlight box won't be updated.
2027     mEventData->mUpdateCursorPosition = false;
2028
2029     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
2030
2031     // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
2032     mEventData->mPrimaryCursorPosition = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2033   }
2034   else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
2035   {
2036     // Nothing to select. i.e. a white space, out of bounds
2037     ChangeState( EventData::EDITING_WITH_POPUP );
2038
2039     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2040
2041     mEventData->mUpdateCursorPosition = true;
2042     mEventData->mUpdateGrabHandlePosition = true;
2043     mEventData->mScrollAfterUpdatePosition = true;
2044     mEventData->mUpdateInputStyle = true;
2045   }
2046   else if( Controller::NoTextTap::NO_ACTION == action )
2047   {
2048     // Nothing to select. i.e. a white space, out of bounds
2049     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2050
2051     mEventData->mUpdateCursorPosition = true;
2052     mEventData->mUpdateGrabHandlePosition = true;
2053     mEventData->mScrollAfterUpdatePosition = true;
2054     mEventData->mUpdateInputStyle = true;
2055   }
2056 }
2057
2058 void Controller::Impl::SetPopupButtons()
2059 {
2060   /**
2061    *  Sets the Popup buttons to be shown depending on State.
2062    *
2063    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
2064    *
2065    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
2066    */
2067
2068   bool isEditable = IsEditable();
2069   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
2070
2071   if( EventData::SELECTING == mEventData->mState )
2072   {
2073     buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::COPY );
2074     if(isEditable)
2075     {
2076       buttonsToShow = TextSelectionPopup::Buttons( buttonsToShow | TextSelectionPopup::CUT );
2077     }
2078
2079     if( !IsClipboardEmpty() )
2080     {
2081       if(isEditable)
2082       {
2083         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2084       }
2085       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2086     }
2087
2088     if( !mEventData->mAllTextSelected )
2089     {
2090       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
2091     }
2092   }
2093   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
2094   {
2095     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
2096     {
2097       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
2098     }
2099
2100     if( !IsClipboardEmpty() )
2101     {
2102       if(isEditable)
2103       {
2104         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2105       }
2106       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2107     }
2108   }
2109   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
2110   {
2111     if ( !IsClipboardEmpty() )
2112     {
2113       if(isEditable)
2114       {
2115         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2116       }
2117       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2118     }
2119   }
2120
2121   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
2122 }
2123
2124 void Controller::Impl::ChangeState( EventData::State newState )
2125 {
2126   if( NULL == mEventData )
2127   {
2128     // Nothing to do if there is no text input.
2129     return;
2130   }
2131
2132   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
2133
2134   if( mEventData->mState != newState )
2135   {
2136     mEventData->mPreviousState = mEventData->mState;
2137     mEventData->mState = newState;
2138
2139     switch( mEventData->mState )
2140     {
2141       case EventData::INACTIVE:
2142       {
2143         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2144         mEventData->mDecorator->StopCursorBlink();
2145         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2146         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2147         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2148         mEventData->mDecorator->SetHighlightActive( false );
2149         mEventData->mDecorator->SetPopupActive( false );
2150         mEventData->mDecoratorUpdated = true;
2151         break;
2152       }
2153       case EventData::INTERRUPTED:
2154       {
2155         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2156         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2157         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2158         mEventData->mDecorator->SetHighlightActive( false );
2159         mEventData->mDecorator->SetPopupActive( false );
2160         mEventData->mDecoratorUpdated = true;
2161         break;
2162       }
2163       case EventData::SELECTING:
2164       {
2165         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2166         mEventData->mDecorator->StopCursorBlink();
2167         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2168         if ( mEventData->mGrabHandleEnabled )
2169         {
2170           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2171           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2172         }
2173         mEventData->mDecorator->SetHighlightActive( true );
2174         if( mEventData->mGrabHandlePopupEnabled )
2175         {
2176           SetPopupButtons();
2177           mEventData->mDecorator->SetPopupActive( true );
2178         }
2179         mEventData->mDecoratorUpdated = true;
2180         break;
2181       }
2182       case EventData::EDITING:
2183       {
2184         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2185         if( mEventData->mCursorBlinkEnabled )
2186         {
2187           mEventData->mDecorator->StartCursorBlink();
2188         }
2189         // Grab handle is not shown until a tap is received whilst EDITING
2190         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2191         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2192         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2193         mEventData->mDecorator->SetHighlightActive( false );
2194         if( mEventData->mGrabHandlePopupEnabled )
2195         {
2196           mEventData->mDecorator->SetPopupActive( false );
2197         }
2198         mEventData->mDecoratorUpdated = true;
2199         break;
2200       }
2201       case EventData::EDITING_WITH_POPUP:
2202       {
2203         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
2204
2205         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2206         if( mEventData->mCursorBlinkEnabled )
2207         {
2208           mEventData->mDecorator->StartCursorBlink();
2209         }
2210         if( mEventData->mSelectionEnabled )
2211         {
2212           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2213           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2214           mEventData->mDecorator->SetHighlightActive( false );
2215         }
2216         else if ( mEventData->mGrabHandleEnabled )
2217         {
2218           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2219         }
2220         if( mEventData->mGrabHandlePopupEnabled )
2221         {
2222           SetPopupButtons();
2223           mEventData->mDecorator->SetPopupActive( true );
2224         }
2225         mEventData->mDecoratorUpdated = true;
2226         break;
2227       }
2228       case EventData::EDITING_WITH_GRAB_HANDLE:
2229       {
2230         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
2231
2232         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2233         if( mEventData->mCursorBlinkEnabled )
2234         {
2235           mEventData->mDecorator->StartCursorBlink();
2236         }
2237         // Grab handle is not shown until a tap is received whilst EDITING
2238         if ( mEventData->mGrabHandleEnabled )
2239         {
2240           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2241         }
2242         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2243         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2244         mEventData->mDecorator->SetHighlightActive( false );
2245         if( mEventData->mGrabHandlePopupEnabled )
2246         {
2247           mEventData->mDecorator->SetPopupActive( false );
2248         }
2249         mEventData->mDecoratorUpdated = true;
2250         break;
2251       }
2252       case EventData::SELECTION_HANDLE_PANNING:
2253       {
2254         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2255         mEventData->mDecorator->StopCursorBlink();
2256         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2257         if ( mEventData->mGrabHandleEnabled )
2258         {
2259           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2260           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2261         }
2262         mEventData->mDecorator->SetHighlightActive( true );
2263         if( mEventData->mGrabHandlePopupEnabled )
2264         {
2265           mEventData->mDecorator->SetPopupActive( false );
2266         }
2267         mEventData->mDecoratorUpdated = true;
2268         break;
2269       }
2270       case EventData::GRAB_HANDLE_PANNING:
2271       {
2272         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
2273
2274         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2275         if( mEventData->mCursorBlinkEnabled )
2276         {
2277           mEventData->mDecorator->StartCursorBlink();
2278         }
2279         if ( mEventData->mGrabHandleEnabled )
2280         {
2281           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2282         }
2283         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2284         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2285         mEventData->mDecorator->SetHighlightActive( false );
2286         if( mEventData->mGrabHandlePopupEnabled )
2287         {
2288           mEventData->mDecorator->SetPopupActive( false );
2289         }
2290         mEventData->mDecoratorUpdated = true;
2291         break;
2292       }
2293       case EventData::EDITING_WITH_PASTE_POPUP:
2294       {
2295         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
2296
2297         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2298         if( mEventData->mCursorBlinkEnabled )
2299         {
2300           mEventData->mDecorator->StartCursorBlink();
2301         }
2302
2303         if ( mEventData->mGrabHandleEnabled )
2304         {
2305           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2306         }
2307         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2308         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2309         mEventData->mDecorator->SetHighlightActive( false );
2310
2311         if( mEventData->mGrabHandlePopupEnabled )
2312         {
2313           SetPopupButtons();
2314           mEventData->mDecorator->SetPopupActive( true );
2315         }
2316         mEventData->mDecoratorUpdated = true;
2317         break;
2318       }
2319       case EventData::TEXT_PANNING:
2320       {
2321         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2322         mEventData->mDecorator->StopCursorBlink();
2323         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2324         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
2325             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
2326         {
2327           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2328           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2329           mEventData->mDecorator->SetHighlightActive( true );
2330         }
2331
2332         if( mEventData->mGrabHandlePopupEnabled )
2333         {
2334           mEventData->mDecorator->SetPopupActive( false );
2335         }
2336
2337         mEventData->mDecoratorUpdated = true;
2338         break;
2339       }
2340     }
2341   }
2342 }
2343
2344 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
2345                                           CursorInfo& cursorInfo )
2346 {
2347   if( !IsShowingRealText() )
2348   {
2349     // Do not want to use the place-holder text to set the cursor position.
2350
2351     // Use the line's height of the font's family set to set the cursor's size.
2352     // If there is no font's family set, use the default font.
2353     // Use the current alignment to place the cursor at the beginning, center or end of the box.
2354
2355     cursorInfo.lineOffset = 0.f;
2356     cursorInfo.lineHeight = GetDefaultFontLineHeight();
2357     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
2358
2359     bool isRTL = false;
2360     if( mModel->mMatchSystemLanguageDirection )
2361     {
2362       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
2363     }
2364
2365     switch( mModel->mHorizontalAlignment )
2366     {
2367       case Text::HorizontalAlignment::BEGIN :
2368       {
2369         if( isRTL )
2370         {
2371           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2372         }
2373         else
2374         {
2375           cursorInfo.primaryPosition.x = 0.f;
2376         }
2377         break;
2378       }
2379       case Text::HorizontalAlignment::CENTER:
2380       {
2381         cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
2382         break;
2383       }
2384       case Text::HorizontalAlignment::END:
2385       {
2386         if( isRTL )
2387         {
2388           cursorInfo.primaryPosition.x = 0.f;
2389         }
2390         else
2391         {
2392           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2393         }
2394         break;
2395       }
2396     }
2397
2398     // Nothing else to do.
2399     return;
2400   }
2401
2402   const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
2403   GetCursorPositionParameters parameters;
2404   parameters.visualModel = mModel->mVisualModel;
2405   parameters.logicalModel = mModel->mLogicalModel;
2406   parameters.metrics = mMetrics;
2407   parameters.logical = logical;
2408   parameters.isMultiline = isMultiLine;
2409
2410   Text::GetCursorPosition( parameters,
2411                            cursorInfo );
2412
2413   // Adds Outline offset.
2414   const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
2415   cursorInfo.primaryPosition.x += outlineWidth;
2416   cursorInfo.primaryPosition.y += outlineWidth;
2417   cursorInfo.secondaryPosition.x += outlineWidth;
2418   cursorInfo.secondaryPosition.y += outlineWidth;
2419
2420   if( isMultiLine )
2421   {
2422     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
2423
2424     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
2425     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
2426
2427     if( 0.f > cursorInfo.primaryPosition.x )
2428     {
2429       cursorInfo.primaryPosition.x = 0.f;
2430     }
2431
2432     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
2433     if( cursorInfo.primaryPosition.x > edgeWidth )
2434     {
2435       cursorInfo.primaryPosition.x = edgeWidth;
2436     }
2437   }
2438 }
2439
2440 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
2441 {
2442   if( NULL == mEventData )
2443   {
2444     // Nothing to do if there is no text input.
2445     return 0u;
2446   }
2447
2448   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
2449
2450   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
2451   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
2452
2453   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
2454   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2455
2456   if( numberOfCharacters > 1u )
2457   {
2458     const Script script = mModel->mLogicalModel->GetScript( index );
2459     if( HasLigatureMustBreak( script ) )
2460     {
2461       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ, ...
2462       numberOfCharacters = 1u;
2463     }
2464   }
2465   else
2466   {
2467     while( 0u == numberOfCharacters )
2468     {
2469       ++glyphIndex;
2470       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2471     }
2472   }
2473
2474   if( index < mEventData->mPrimaryCursorPosition )
2475   {
2476     cursorIndex -= numberOfCharacters;
2477   }
2478   else
2479   {
2480     cursorIndex += numberOfCharacters;
2481   }
2482
2483   // Will update the cursor hook position.
2484   mEventData->mUpdateCursorHookPosition = true;
2485
2486   return cursorIndex;
2487 }
2488
2489 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
2490 {
2491   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
2492   if( NULL == mEventData )
2493   {
2494     // Nothing to do if there is no text input.
2495     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
2496     return;
2497   }
2498
2499   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
2500
2501   mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
2502
2503   // Sets the cursor position.
2504   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
2505                                        cursorPosition.x,
2506                                        cursorPosition.y,
2507                                        cursorInfo.primaryCursorHeight,
2508                                        cursorInfo.lineHeight );
2509   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
2510
2511   if( mEventData->mUpdateGrabHandlePosition )
2512   {
2513     // Sets the grab handle position.
2514     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
2515                                          cursorPosition.x,
2516                                          cursorInfo.lineOffset + mModel->mScrollPosition.y,
2517                                          cursorInfo.lineHeight );
2518   }
2519
2520   if( cursorInfo.isSecondaryCursor )
2521   {
2522     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
2523                                          cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
2524                                          cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
2525                                          cursorInfo.secondaryCursorHeight,
2526                                          cursorInfo.lineHeight );
2527     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
2528   }
2529
2530   // Set which cursors are active according the state.
2531   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
2532   {
2533     if( cursorInfo.isSecondaryCursor )
2534     {
2535       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
2536     }
2537     else
2538     {
2539       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2540     }
2541   }
2542   else
2543   {
2544     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2545   }
2546
2547   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
2548 }
2549
2550 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
2551                                               const CursorInfo& cursorInfo )
2552 {
2553   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
2554       ( RIGHT_SELECTION_HANDLE != handleType ) )
2555   {
2556     return;
2557   }
2558
2559   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
2560
2561   // Sets the handle's position.
2562   mEventData->mDecorator->SetPosition( handleType,
2563                                        cursorPosition.x,
2564                                        cursorInfo.lineOffset + mModel->mScrollPosition.y,
2565                                        cursorInfo.lineHeight );
2566
2567   // If selection handle at start of the text and other at end of the text then all text is selected.
2568   const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2569   const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2570   mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mModel->mLogicalModel->mText.Count() );
2571 }
2572
2573 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
2574 {
2575   // Clamp between -space & -alignment offset.
2576
2577   if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
2578   {
2579     const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
2580     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
2581     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
2582
2583     mEventData->mDecoratorUpdated = true;
2584   }
2585   else
2586   {
2587     mModel->mScrollPosition.x = 0.f;
2588   }
2589 }
2590
2591 void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
2592 {
2593   if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
2594   {
2595     // Nothing to do if the text is single line.
2596     return;
2597   }
2598
2599   // Clamp between -space & 0.
2600   if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
2601   {
2602     const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
2603     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
2604     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
2605
2606     mEventData->mDecoratorUpdated = true;
2607   }
2608   else
2609   {
2610     mModel->mScrollPosition.y = 0.f;
2611   }
2612 }
2613
2614 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
2615 {
2616   const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
2617
2618   // position is in actor's coords.
2619   const float positionEndX = position.x + cursorWidth;
2620   const float positionEndY = position.y + lineHeight;
2621
2622   // Transform the position to decorator coords.
2623   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
2624   const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
2625
2626   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
2627   const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
2628
2629   if( decoratorPositionBeginX < 0.f )
2630   {
2631     mModel->mScrollPosition.x = -position.x;
2632   }
2633   else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
2634   {
2635     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
2636   }
2637
2638   if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
2639   {
2640     if( decoratorPositionBeginY < 0.f )
2641     {
2642       mModel->mScrollPosition.y = -position.y;
2643     }
2644     else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
2645     {
2646       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
2647     }
2648   }
2649 }
2650
2651 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
2652 {
2653   // Get the current cursor position in decorator coords.
2654   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2655
2656   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
2657
2658
2659
2660   // Calculate the offset to match the cursor position before the character was deleted.
2661   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
2662
2663   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
2664   if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
2665   {
2666     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
2667     mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
2668   }
2669
2670
2671   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
2672   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
2673
2674   // Makes the new cursor position visible if needed.
2675   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
2676 }
2677
2678 void Controller::Impl::RequestRelayout()
2679 {
2680   if( NULL != mControlInterface )
2681   {
2682     mControlInterface->RequestTextRelayout();
2683   }
2684 }
2685
2686 Actor Controller::Impl::CreateBackgroundActor()
2687 {
2688   // NOTE: Currently we only support background color for one line left-to-right text,
2689   //       so the following calculation is based on one line left-to-right text only!
2690
2691   Actor actor;
2692
2693   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
2694   if( numberOfGlyphs > 0u )
2695   {
2696     Vector<GlyphInfo> glyphs;
2697     glyphs.Resize( numberOfGlyphs );
2698
2699     Vector<Vector2> positions;
2700     positions.Resize( numberOfGlyphs );
2701
2702     // Get the line where the glyphs are laid-out.
2703     const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
2704     float alignmentOffset = lineRun->alignmentOffset;
2705     numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
2706                                       positions.Begin(),
2707                                       alignmentOffset,
2708                                       0u,
2709                                       numberOfGlyphs );
2710
2711     glyphs.Resize( numberOfGlyphs );
2712     positions.Resize( numberOfGlyphs );
2713
2714     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
2715     const Vector2* const positionsBuffer = positions.Begin();
2716
2717     BackgroundMesh mesh;
2718     mesh.mVertices.Reserve( 4u * glyphs.Size() );
2719     mesh.mIndices.Reserve( 6u * glyphs.Size() );
2720
2721     const Vector2 textSize = mView.GetLayoutSize();
2722
2723     const float offsetX = textSize.width * 0.5f;
2724     const float offsetY = textSize.height * 0.5f;
2725
2726     const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
2727     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
2728     const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
2729
2730     Vector4 quad;
2731     uint32_t numberOfQuads = 0u;
2732
2733     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
2734     {
2735       const GlyphInfo& glyph = *( glyphsBuffer + i );
2736
2737       // Get the background color of the character.
2738       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
2739       const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
2740       const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? defaultBackgroundColor : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
2741
2742       // Only create quads for glyphs with a background color
2743       if ( backgroundColor != Color::TRANSPARENT )
2744       {
2745         const Vector2 position = *( positionsBuffer + i );
2746
2747         if ( i == 0u && glyphSize == 1u ) // Only one glyph in the whole text
2748         {
2749           quad.x = position.x;
2750           quad.y = 0.0f;
2751           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
2752           quad.w = textSize.height;
2753         }
2754         else if ( i == 0u ) // The first glyph in the whole text
2755         {
2756           quad.x = position.x;
2757           quad.y = 0.0f;
2758           quad.z = quad.x - glyph.xBearing + glyph.advance;
2759           quad.w = textSize.height;
2760         }
2761         else if ( i == glyphSize - 1u ) // The last glyph in the whole text
2762         {
2763           quad.x = position.x - glyph.xBearing;
2764           quad.y = 0.0f;
2765           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
2766           quad.w = textSize.height;
2767         }
2768         else // The glyph in the middle of the text
2769         {
2770           quad.x = position.x - glyph.xBearing;
2771           quad.y = 0.0f;
2772           quad.z = quad.x + glyph.advance;
2773           quad.w = textSize.height;
2774         }
2775
2776         BackgroundVertex vertex;
2777
2778         // Top left
2779         vertex.mPosition.x = quad.x - offsetX;
2780         vertex.mPosition.y = quad.y - offsetY;
2781         vertex.mColor = backgroundColor;
2782         mesh.mVertices.PushBack( vertex );
2783
2784         // Top right
2785         vertex.mPosition.x = quad.z - offsetX;
2786         vertex.mPosition.y = quad.y - offsetY;
2787         vertex.mColor = backgroundColor;
2788         mesh.mVertices.PushBack( vertex );
2789
2790         // Bottom left
2791         vertex.mPosition.x = quad.x - offsetX;
2792         vertex.mPosition.y = quad.w - offsetY;
2793         vertex.mColor = backgroundColor;
2794         mesh.mVertices.PushBack( vertex );
2795
2796         // Bottom right
2797         vertex.mPosition.x = quad.z - offsetX;
2798         vertex.mPosition.y = quad.w - offsetY;
2799         vertex.mColor = backgroundColor;
2800         mesh.mVertices.PushBack( vertex );
2801
2802         // Six indices in counter clockwise winding
2803         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
2804         mesh.mIndices.PushBack( 0u + 4 * numberOfQuads );
2805         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
2806         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
2807         mesh.mIndices.PushBack( 3u + 4 * numberOfQuads );
2808         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
2809
2810         numberOfQuads++;
2811       }
2812     }
2813
2814     // Only create the background actor if there are glyphs with background color
2815     if ( mesh.mVertices.Count() > 0u )
2816     {
2817       Property::Map quadVertexFormat;
2818       quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
2819       quadVertexFormat[ "aColor" ] = Property::VECTOR4;
2820
2821       VertexBuffer quadVertices = VertexBuffer::New( quadVertexFormat );
2822       quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
2823
2824       Geometry quadGeometry = Geometry::New();
2825       quadGeometry.AddVertexBuffer( quadVertices );
2826       quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
2827
2828       if( !mShaderBackground )
2829       {
2830         mShaderBackground = Shader::New( VERTEX_SHADER_BACKGROUND, FRAGMENT_SHADER_BACKGROUND );
2831       }
2832
2833       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
2834       renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
2835       renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
2836
2837       actor = Actor::New();
2838       actor.SetProperty( Dali::Actor::Property::NAME, "TextBackgroundColorActor" );
2839       actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
2840       actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
2841       actor.SetProperty( Actor::Property::SIZE, textSize );
2842       actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR );
2843       actor.AddRenderer( renderer );
2844     }
2845   }
2846
2847   return actor;
2848 }
2849
2850 } // namespace Text
2851
2852 } // namespace Toolkit
2853
2854 } // namespace Dali