Further refactoring of text-controller-impl
[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
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
27 #include <dali-toolkit/internal/text/bidirectional-support.h>
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/color-segmentation.h>
30 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
31 #include <dali-toolkit/internal/text/multi-language-support.h>
32 #include <dali-toolkit/internal/text/segmentation.h>
33 #include <dali-toolkit/internal/text/shaper.h>
34 #include <dali-toolkit/internal/text/text-control-interface.h>
35 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
36 #include <dali-toolkit/internal/text/text-run-container.h>
37 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
38
39 using namespace Dali;
40
41 namespace
42 {
43
44 #if defined(DEBUG_ENABLED)
45 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
46 #endif
47
48 #define MAKE_SHADER(A)#A
49
50 const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
51 attribute mediump vec2    aPosition;
52 attribute mediump vec4    aColor;
53 varying   mediump vec4    vColor;
54 uniform   highp mat4      uMvpMatrix;
55
56 void main()
57 {
58   mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
59   gl_Position = uMvpMatrix * position;
60   vColor = aColor;
61 }
62 );
63
64 const char* FRAGMENT_SHADER_BACKGROUND = MAKE_SHADER(
65 varying mediump vec4      vColor;
66 uniform lowp    vec4      uColor;
67
68 void main()
69 {
70   gl_FragColor = vColor * uColor;
71 }
72 );
73
74 struct BackgroundVertex
75 {
76   Vector2 mPosition;        ///< Vertex posiiton
77   Vector4 mColor;           ///< Vertex color
78 };
79
80 struct BackgroundMesh
81 {
82   Vector< BackgroundVertex > mVertices;    ///< container of vertices
83   Vector< unsigned short > mIndices;       ///< container of indices
84 };
85
86 const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f );
87 const Dali::Vector4 BACKGROUND_SUB4( 0.58f, 0.87f, 0.96f, 1.f );
88 const Dali::Vector4 BACKGROUND_SUB5( 0.83f, 0.94f, 0.98f, 1.f );
89 const Dali::Vector4 BACKGROUND_SUB6( 1.f, 0.5f, 0.5f, 1.f );
90 const Dali::Vector4 BACKGROUND_SUB7( 1.f, 0.8f, 0.8f, 1.f );
91
92 } // namespace
93
94 namespace Dali
95 {
96
97 namespace Toolkit
98 {
99
100 namespace Text
101 {
102
103 EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
104 : mDecorator( decorator ),
105   mInputMethodContext( inputMethodContext ),
106   mPlaceholderFont( NULL ),
107   mPlaceholderTextActive(),
108   mPlaceholderTextInactive(),
109   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
110   mEventQueue(),
111   mInputStyleChangedQueue(),
112   mPreviousState( INACTIVE ),
113   mState( INACTIVE ),
114   mPrimaryCursorPosition( 0u ),
115   mLeftSelectionPosition( 0u ),
116   mRightSelectionPosition( 0u ),
117   mPreEditStartPosition( 0u ),
118   mPreEditLength( 0u ),
119   mCursorHookPositionX( 0.f ),
120   mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
121   mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
122   mIsShowingPlaceholderText( false ),
123   mPreEditFlag( false ),
124   mDecoratorUpdated( false ),
125   mCursorBlinkEnabled( true ),
126   mGrabHandleEnabled( true ),
127   mGrabHandlePopupEnabled( true ),
128   mSelectionEnabled( true ),
129   mUpdateCursorHookPosition( false ),
130   mUpdateCursorPosition( false ),
131   mUpdateGrabHandlePosition( false ),
132   mUpdateLeftSelectionPosition( false ),
133   mUpdateRightSelectionPosition( false ),
134   mIsLeftHandleSelected( false ),
135   mIsRightHandleSelected( false ),
136   mUpdateHighlightBox( false ),
137   mScrollAfterUpdatePosition( false ),
138   mScrollAfterDelete( false ),
139   mAllTextSelected( false ),
140   mUpdateInputStyle( false ),
141   mPasswordInput( false ),
142   mCheckScrollAmount( false ),
143   mIsPlaceholderPixelSize( false ),
144   mIsPlaceholderElideEnabled( false ),
145   mPlaceholderEllipsisFlag( false ),
146   mShiftSelectionFlag( true ),
147   mUpdateAlignment( false ),
148   mEditingEnabled( true )
149 {
150 }
151
152 bool Controller::Impl::ProcessInputEvents()
153 {
154   return ControllerImplEventHandler::ProcessInputEvents(*this);
155 }
156
157 void Controller::Impl::NotifyInputMethodContext()
158 {
159   if( mEventData && mEventData->mInputMethodContext )
160   {
161     CharacterIndex cursorPosition = GetLogicalCursorPosition();
162
163     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
164
165     // Update the cursor position by removing the initial white spaces.
166     if( cursorPosition < numberOfWhiteSpaces )
167     {
168       cursorPosition = 0u;
169     }
170     else
171     {
172       cursorPosition -= numberOfWhiteSpaces;
173     }
174
175     mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
176     mEventData->mInputMethodContext.NotifyCursorPosition();
177   }
178 }
179
180 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
181 {
182   if ( mEventData && mEventData->mInputMethodContext )
183   {
184     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
185     mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
186   }
187 }
188
189 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
190 {
191   CharacterIndex cursorPosition = 0u;
192
193   if( mEventData )
194   {
195     if( ( EventData::SELECTING == mEventData->mState ) ||
196         ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
197     {
198       cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
199     }
200     else
201     {
202       cursorPosition = mEventData->mPrimaryCursorPosition;
203     }
204   }
205
206   return cursorPosition;
207 }
208
209 Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
210 {
211   Length numberOfWhiteSpaces = 0u;
212
213   // Get the buffer to the text.
214   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
215
216   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
217   for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
218   {
219     if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
220     {
221       break;
222     }
223   }
224
225   return numberOfWhiteSpaces;
226 }
227
228 void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
229 {
230   // Get the total number of characters.
231   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
232
233   // Retrieve the text.
234   if( 0u != numberOfCharacters )
235   {
236     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
237   }
238 }
239
240 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
241 {
242   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
243   mTextUpdateInfo.mStartGlyphIndex = 0u;
244   mTextUpdateInfo.mStartLineIndex = 0u;
245   numberOfCharacters = 0u;
246
247   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
248   if( 0u == numberOfParagraphs )
249   {
250     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
251     numberOfCharacters = 0u;
252
253     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
254
255     // Nothing else to do if there are no paragraphs.
256     return;
257   }
258
259   // Find the paragraphs to be updated.
260   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
261   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
262   {
263     // Text is being added at the end of the current text.
264     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
265     {
266       // Text is being added in a new paragraph after the last character of the text.
267       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
268       numberOfCharacters = 0u;
269       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
270
271       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
272       mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
273
274       // Nothing else to do;
275       return;
276     }
277
278     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
279   }
280   else
281   {
282     Length numberOfCharactersToUpdate = 0u;
283     if( mTextUpdateInfo.mFullRelayoutNeeded )
284     {
285       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
286     }
287     else
288     {
289       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
290     }
291     mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
292                                            numberOfCharactersToUpdate,
293                                            paragraphsToBeUpdated );
294   }
295
296   if( 0u != paragraphsToBeUpdated.Count() )
297   {
298     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
299     const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
300     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
301
302     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
303     const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
304
305     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
306         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
307         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
308           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
309     {
310       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
311       const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
312
313       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
314     }
315     else
316     {
317       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
318     }
319   }
320
321   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
322   mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
323 }
324
325 void Controller::Impl::ClearFullModelData( OperationsMask operations )
326 {
327   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
328   {
329     mModel->mLogicalModel->mLineBreakInfo.Clear();
330     mModel->mLogicalModel->mParagraphInfo.Clear();
331   }
332
333   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
334   {
335     mModel->mLogicalModel->mScriptRuns.Clear();
336   }
337
338   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
339   {
340     mModel->mLogicalModel->mFontRuns.Clear();
341   }
342
343   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
344   {
345     if( NO_OPERATION != ( BIDI_INFO & operations ) )
346     {
347       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
348       mModel->mLogicalModel->mCharacterDirections.Clear();
349     }
350
351     if( NO_OPERATION != ( REORDER & operations ) )
352     {
353       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
354       for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
355              endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
356            it != endIt;
357            ++it )
358       {
359         BidirectionalLineInfoRun& bidiLineInfo = *it;
360
361         free( bidiLineInfo.visualToLogicalMap );
362         bidiLineInfo.visualToLogicalMap = NULL;
363       }
364       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
365     }
366   }
367
368   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
369   {
370     mModel->mVisualModel->mGlyphs.Clear();
371     mModel->mVisualModel->mGlyphsToCharacters.Clear();
372     mModel->mVisualModel->mCharactersToGlyph.Clear();
373     mModel->mVisualModel->mCharactersPerGlyph.Clear();
374     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
375     mModel->mVisualModel->mGlyphPositions.Clear();
376   }
377
378   if( NO_OPERATION != ( LAYOUT & operations ) )
379   {
380     mModel->mVisualModel->mLines.Clear();
381   }
382
383   if( NO_OPERATION != ( COLOR & operations ) )
384   {
385     mModel->mVisualModel->mColorIndices.Clear();
386     mModel->mVisualModel->mBackgroundColorIndices.Clear();
387   }
388 }
389
390 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
391 {
392   const CharacterIndex endIndexPlusOne = endIndex + 1u;
393
394   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
395   {
396     // Clear the line break info.
397     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
398
399     mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
400                                                  lineBreakInfoBuffer + endIndexPlusOne );
401
402     // Clear the paragraphs.
403     ClearCharacterRuns( startIndex,
404                         endIndex,
405                         mModel->mLogicalModel->mParagraphInfo );
406   }
407
408   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
409   {
410     // Clear the scripts.
411     ClearCharacterRuns( startIndex,
412                         endIndex,
413                         mModel->mLogicalModel->mScriptRuns );
414   }
415
416   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
417   {
418     // Clear the fonts.
419     ClearCharacterRuns( startIndex,
420                         endIndex,
421                         mModel->mLogicalModel->mFontRuns );
422   }
423
424   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
425   {
426     if( NO_OPERATION != ( BIDI_INFO & operations ) )
427     {
428       // Clear the bidirectional paragraph info.
429       ClearCharacterRuns( startIndex,
430                           endIndex,
431                           mModel->mLogicalModel->mBidirectionalParagraphInfo );
432
433       // Clear the character's directions.
434       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
435
436       mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
437                                                          characterDirectionsBuffer + endIndexPlusOne );
438     }
439
440     if( NO_OPERATION != ( REORDER & operations ) )
441     {
442       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
443       uint32_t endRemoveIndex = startRemoveIndex;
444       ClearCharacterRuns( startIndex,
445                           endIndex,
446                           mModel->mLogicalModel->mBidirectionalLineInfo,
447                           startRemoveIndex,
448                           endRemoveIndex );
449
450       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
451
452       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
453       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
454              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
455            it != endIt;
456            ++it )
457       {
458         BidirectionalLineInfoRun& bidiLineInfo = *it;
459
460         free( bidiLineInfo.visualToLogicalMap );
461         bidiLineInfo.visualToLogicalMap = NULL;
462       }
463
464       mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
465                                                            bidirectionalLineInfoBuffer + endRemoveIndex );
466     }
467   }
468 }
469
470 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
471 {
472   const CharacterIndex endIndexPlusOne = endIndex + 1u;
473   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
474
475   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
476   GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
477   Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
478
479   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
480   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
481
482   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
483   {
484     // Update the character to glyph indices.
485     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
486            endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
487          it != endIt;
488          ++it )
489     {
490       CharacterIndex& index = *it;
491       index -= numberOfGlyphsRemoved;
492     }
493
494     // Clear the character to glyph conversion table.
495     mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
496                                                     charactersToGlyphBuffer + endIndexPlusOne );
497
498     // Clear the glyphs per character table.
499     mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
500                                                      glyphsPerCharacterBuffer + endIndexPlusOne );
501
502     // Clear the glyphs buffer.
503     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
504     mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
505                                          glyphsBuffer + endGlyphIndexPlusOne );
506
507     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
508
509     // Update the glyph to character indices.
510     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
511            endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
512          it != endIt;
513          ++it )
514     {
515       CharacterIndex& index = *it;
516       index -= numberOfCharactersRemoved;
517     }
518
519     // Clear the glyphs to characters buffer.
520     mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
521                                                      glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
522
523     // Clear the characters per glyph buffer.
524     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
525     mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
526                                                      charactersPerGlyphBuffer + endGlyphIndexPlusOne );
527
528     // Clear the positions buffer.
529     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
530     mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
531                                                  positionsBuffer + endGlyphIndexPlusOne );
532   }
533
534   if( NO_OPERATION != ( LAYOUT & operations ) )
535   {
536     // Clear the lines.
537     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
538     uint32_t endRemoveIndex = startRemoveIndex;
539     ClearCharacterRuns( startIndex,
540                         endIndex,
541                         mModel->mVisualModel->mLines,
542                         startRemoveIndex,
543                         endRemoveIndex );
544
545     // Will update the glyph runs.
546     startRemoveIndex = mModel->mVisualModel->mLines.Count();
547     endRemoveIndex = startRemoveIndex;
548     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
549                     endGlyphIndexPlusOne - 1u,
550                     mModel->mVisualModel->mLines,
551                     startRemoveIndex,
552                     endRemoveIndex );
553
554     // Set the line index from where to insert the new laid-out lines.
555     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
556
557     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
558     mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
559                                         linesBuffer + endRemoveIndex );
560   }
561
562   if( NO_OPERATION != ( COLOR & operations ) )
563   {
564     if( 0u != mModel->mVisualModel->mColorIndices.Count() )
565     {
566       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
567       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
568                                                  colorIndexBuffer + endGlyphIndexPlusOne );
569     }
570
571     if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
572     {
573       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
574       mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
575                                                            backgroundColorIndexBuffer + endGlyphIndexPlusOne );
576     }
577   }
578 }
579
580 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
581 {
582   if( mTextUpdateInfo.mClearAll ||
583       ( ( 0u == startIndex ) &&
584         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
585   {
586     ClearFullModelData( operations );
587   }
588   else
589   {
590     // Clear the model data related with characters.
591     ClearCharacterModelData( startIndex, endIndex, operations );
592
593     // Clear the model data related with glyphs.
594     ClearGlyphModelData( startIndex, endIndex, operations );
595   }
596
597   // The estimated number of lines. Used to avoid reallocations when layouting.
598   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
599
600   mModel->mVisualModel->ClearCaches();
601 }
602
603 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
604 {
605   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
606
607   // Calculate the operations to be done.
608   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
609
610   if( NO_OPERATION == operations )
611   {
612     // Nothing to do if no operations are pending and required.
613     return false;
614   }
615
616   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
617   Vector<Character> displayCharacters;
618   bool useHiddenText = false;
619   if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
620   {
621     mHiddenInput->Substitute( srcCharacters,displayCharacters );
622     useHiddenText = true;
623   }
624
625   Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
626   const Length numberOfCharacters = utf32Characters.Count();
627
628   // Index to the first character of the first paragraph to be updated.
629   CharacterIndex startIndex = 0u;
630   // Number of characters of the paragraphs to be removed.
631   Length paragraphCharacters = 0u;
632
633   CalculateTextUpdateIndices( paragraphCharacters );
634
635   // Check whether the indices for updating the text is valid
636   if ( numberOfCharacters > 0u &&
637        ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
638          mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
639   {
640     std::string currentText;
641     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
642
643     DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
644     DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
645
646     // Dump mTextUpdateInfo
647     DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
648     DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
649     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
650     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
651     DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
652     DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
653     DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
654     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
655     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
656     DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
657     DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
658     DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
659     DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
660
661     return false;
662   }
663
664   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
665
666   if( mTextUpdateInfo.mClearAll ||
667       ( 0u != paragraphCharacters ) )
668   {
669     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
670   }
671
672   mTextUpdateInfo.mClearAll = false;
673
674   // Whether the model is updated.
675   bool updated = false;
676
677   Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
678   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
679
680   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
681   {
682     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
683     // calculate the bidirectional info for each 'paragraph'.
684     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
685     // is not shaped together).
686     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
687
688     SetLineBreakInfo( utf32Characters,
689                       startIndex,
690                       requestedNumberOfCharacters,
691                       lineBreakInfo );
692
693     // Create the paragraph info.
694     mModel->mLogicalModel->CreateParagraphInfo( startIndex,
695                                                 requestedNumberOfCharacters );
696     updated = true;
697   }
698
699   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
700   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
701
702   Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
703   Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
704
705   if( getScripts || validateFonts )
706   {
707     // Validates the fonts assigned by the application or assigns default ones.
708     // It makes sure all the characters are going to be rendered by the correct font.
709     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
710
711     if( getScripts )
712     {
713       // Retrieves the scripts used in the text.
714       multilanguageSupport.SetScripts( utf32Characters,
715                                        startIndex,
716                                        requestedNumberOfCharacters,
717                                        scripts );
718     }
719
720     if( validateFonts )
721     {
722       // Validate the fonts set through the mark-up string.
723       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
724
725       // Get the default font's description.
726       TextAbstraction::FontDescription defaultFontDescription;
727       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
728
729       if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
730       {
731         // If the placeholder font is set specifically, only placeholder font is changed.
732         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
733         if( mEventData->mPlaceholderFont->sizeDefined )
734         {
735           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * 64u;
736         }
737       }
738       else if( NULL != mFontDefaults )
739       {
740         // Set the normal font and the placeholder font.
741         defaultFontDescription = mFontDefaults->mFontDescription;
742
743         if( mTextFitEnabled )
744         {
745           defaultPointSize = mFontDefaults->mFitPointSize * 64u;
746         }
747         else
748         {
749           defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * 64u;
750         }
751       }
752
753       // Validates the fonts. If there is a character with no assigned font it sets a default one.
754       // After this call, fonts are validated.
755       multilanguageSupport.ValidateFonts( utf32Characters,
756                                           scripts,
757                                           fontDescriptionRuns,
758                                           defaultFontDescription,
759                                           defaultPointSize,
760                                           startIndex,
761                                           requestedNumberOfCharacters,
762                                           validFonts );
763     }
764     updated = true;
765   }
766
767   Vector<Character> mirroredUtf32Characters;
768   bool textMirrored = false;
769   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
770   if( NO_OPERATION != ( BIDI_INFO & operations ) )
771   {
772     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
773     bidirectionalInfo.Reserve( numberOfParagraphs );
774
775     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
776     SetBidirectionalInfo( utf32Characters,
777                           scripts,
778                           lineBreakInfo,
779                           startIndex,
780                           requestedNumberOfCharacters,
781                           bidirectionalInfo,
782                           mModel->mMatchSystemLanguageDirection,
783                           mLayoutDirection );
784
785     if( 0u != bidirectionalInfo.Count() )
786     {
787       // Only set the character directions if there is right to left characters.
788       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
789       GetCharactersDirection( bidirectionalInfo,
790                               numberOfCharacters,
791                               startIndex,
792                               requestedNumberOfCharacters,
793                               directions );
794
795       // This paragraph has right to left text. Some characters may need to be mirrored.
796       // TODO: consider if the mirrored string can be stored as well.
797
798       textMirrored = GetMirroredText( utf32Characters,
799                                       directions,
800                                       bidirectionalInfo,
801                                       startIndex,
802                                       requestedNumberOfCharacters,
803                                       mirroredUtf32Characters );
804     }
805     else
806     {
807       // There is no right to left characters. Clear the directions vector.
808       mModel->mLogicalModel->mCharacterDirections.Clear();
809     }
810     updated = true;
811   }
812
813   Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
814   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
815   Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
816   Vector<GlyphIndex> newParagraphGlyphs;
817   newParagraphGlyphs.Reserve( numberOfParagraphs );
818
819   const Length currentNumberOfGlyphs = glyphs.Count();
820   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
821   {
822     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
823     // Shapes the text.
824     ShapeText( textToShape,
825                lineBreakInfo,
826                scripts,
827                validFonts,
828                startIndex,
829                mTextUpdateInfo.mStartGlyphIndex,
830                requestedNumberOfCharacters,
831                glyphs,
832                glyphsToCharactersMap,
833                charactersPerGlyph,
834                newParagraphGlyphs );
835
836     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
837     mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
838     mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
839     updated = true;
840   }
841
842   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
843
844   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
845   {
846     GlyphInfo* glyphsBuffer = glyphs.Begin();
847     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
848
849     // Update the width and advance of all new paragraph characters.
850     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
851     {
852       const GlyphIndex index = *it;
853       GlyphInfo& glyph = *( glyphsBuffer + index );
854
855       glyph.xBearing = 0.f;
856       glyph.width = 0.f;
857       glyph.advance = 0.f;
858     }
859     updated = true;
860   }
861
862   if( ( NULL != mEventData ) &&
863       mEventData->mPreEditFlag &&
864       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
865   {
866     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
867     mEventData->mInputMethodContext.GetPreeditStyle( attrs );
868     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
869
870     // Check the type of preedit and run it.
871     for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
872     {
873       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
874       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex  );
875       type = attrData.preeditType;
876
877       // Check the number of commit characters for the start position.
878       unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
879       Length numberOfIndices = attrData.endIndex - attrData.startIndex;
880
881       switch( type )
882       {
883         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
884         {
885           // Add the underline for the pre-edit text.
886           GlyphRun underlineRun;
887           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
888           underlineRun.numberOfGlyphs = numberOfIndices;
889           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
890           break;
891         }
892         case Dali::InputMethodContext::PreeditStyle::REVERSE:
893         {
894           Vector4 textColor = mModel->mVisualModel->GetTextColor();
895           ColorRun backgroundColorRun;
896           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
897           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
898           backgroundColorRun.color = textColor;
899           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
900
901           Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
902           Vector<ColorRun>  colorRuns;
903           colorRuns.Resize( 1u );
904           ColorRun& colorRun = *( colorRuns.Begin() );
905           colorRun.color = backgroundColor;
906           colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
907           colorRun.characterRun.numberOfCharacters = numberOfIndices;
908
909           mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
910           break;
911         }
912         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
913         {
914           ColorRun backgroundColorRun;
915           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
916           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
917           backgroundColorRun.color = LIGHT_BLUE;
918           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
919           break;
920         }
921         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
922         {
923           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
924           ColorRun backgroundColorRun;
925           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
926           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
927           backgroundColorRun.color = BACKGROUND_SUB4;
928           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
929
930           GlyphRun underlineRun;
931           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
932           underlineRun.numberOfGlyphs = numberOfIndices;
933           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
934           break;
935         }
936         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
937         {
938           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
939           ColorRun backgroundColorRun;
940           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
941           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
942           backgroundColorRun.color = BACKGROUND_SUB5;
943           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
944
945           GlyphRun underlineRun;
946           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
947           underlineRun.numberOfGlyphs = numberOfIndices;
948           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
949           break;
950         }
951         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
952         {
953           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
954           ColorRun backgroundColorRun;
955           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
956           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
957           backgroundColorRun.color = BACKGROUND_SUB6;
958           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
959
960           GlyphRun underlineRun;
961           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
962           underlineRun.numberOfGlyphs = numberOfIndices;
963           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
964           break;
965         }
966         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
967         {
968           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
969           ColorRun backgroundColorRun;
970           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
971           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
972           backgroundColorRun.color = BACKGROUND_SUB7;
973           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
974
975           GlyphRun underlineRun;
976           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
977           underlineRun.numberOfGlyphs = numberOfIndices;
978           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
979           break;
980         }
981         case Dali::InputMethodContext::PreeditStyle::NONE:
982         default:
983         {
984           break;
985         }
986       }
987     }
988     attrs.Clear();
989     updated = true;
990   }
991
992   if( NO_OPERATION != ( COLOR & operations ) )
993   {
994     // Set the color runs in glyphs.
995     SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
996                               mModel->mVisualModel->mCharactersToGlyph,
997                               mModel->mVisualModel->mGlyphsPerCharacter,
998                               startIndex,
999                               mTextUpdateInfo.mStartGlyphIndex,
1000                               requestedNumberOfCharacters,
1001                               mModel->mVisualModel->mColors,
1002                               mModel->mVisualModel->mColorIndices );
1003
1004     // Set the background color runs in glyphs.
1005     SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
1006                               mModel->mVisualModel->mCharactersToGlyph,
1007                               mModel->mVisualModel->mGlyphsPerCharacter,
1008                               startIndex,
1009                               mTextUpdateInfo.mStartGlyphIndex,
1010                               requestedNumberOfCharacters,
1011                               mModel->mVisualModel->mBackgroundColors,
1012                               mModel->mVisualModel->mBackgroundColorIndices );
1013
1014     updated = true;
1015   }
1016
1017
1018   // The estimated number of lines. Used to avoid reallocations when layouting.
1019   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
1020
1021   // Set the previous number of characters for the next time the text is updated.
1022   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1023
1024   return updated;
1025 }
1026
1027 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
1028 {
1029   // Sets the default text's color.
1030   inputStyle.textColor = mTextColor;
1031   inputStyle.isDefaultColor = true;
1032
1033   inputStyle.familyName.clear();
1034   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1035   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
1036   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
1037   inputStyle.size = 0.f;
1038
1039   inputStyle.lineSpacing = 0.f;
1040
1041   inputStyle.underlineProperties.clear();
1042   inputStyle.shadowProperties.clear();
1043   inputStyle.embossProperties.clear();
1044   inputStyle.outlineProperties.clear();
1045
1046   inputStyle.isFamilyDefined = false;
1047   inputStyle.isWeightDefined = false;
1048   inputStyle.isWidthDefined = false;
1049   inputStyle.isSlantDefined = false;
1050   inputStyle.isSizeDefined = false;
1051
1052   inputStyle.isLineSpacingDefined = false;
1053
1054   inputStyle.isUnderlineDefined = false;
1055   inputStyle.isShadowDefined = false;
1056   inputStyle.isEmbossDefined = false;
1057   inputStyle.isOutlineDefined = false;
1058
1059   // Sets the default font's family name, weight, width, slant and size.
1060   if( mFontDefaults )
1061   {
1062     if( mFontDefaults->familyDefined )
1063     {
1064       inputStyle.familyName = mFontDefaults->mFontDescription.family;
1065       inputStyle.isFamilyDefined = true;
1066     }
1067
1068     if( mFontDefaults->weightDefined )
1069     {
1070       inputStyle.weight = mFontDefaults->mFontDescription.weight;
1071       inputStyle.isWeightDefined = true;
1072     }
1073
1074     if( mFontDefaults->widthDefined )
1075     {
1076       inputStyle.width = mFontDefaults->mFontDescription.width;
1077       inputStyle.isWidthDefined = true;
1078     }
1079
1080     if( mFontDefaults->slantDefined )
1081     {
1082       inputStyle.slant = mFontDefaults->mFontDescription.slant;
1083       inputStyle.isSlantDefined = true;
1084     }
1085
1086     if( mFontDefaults->sizeDefined )
1087     {
1088       inputStyle.size = mFontDefaults->mDefaultPointSize;
1089       inputStyle.isSizeDefined = true;
1090     }
1091   }
1092 }
1093
1094 float Controller::Impl::GetDefaultFontLineHeight()
1095 {
1096   FontId defaultFontId = 0u;
1097   if( NULL == mFontDefaults )
1098   {
1099     TextAbstraction::FontDescription fontDescription;
1100     defaultFontId = mFontClient.GetFontId( fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale );
1101   }
1102   else
1103   {
1104     defaultFontId = mFontDefaults->GetFontId( mFontClient, mFontDefaults->mDefaultPointSize * mFontSizeScale );
1105   }
1106
1107   Text::FontMetrics fontMetrics;
1108   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
1109
1110   return( fontMetrics.ascender - fontMetrics.descender );
1111 }
1112
1113 void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint32_t *pEnd)
1114 {
1115   if( nullptr == mEventData )
1116   {
1117     // Nothing to do if there is no text.
1118     return;
1119   }
1120
1121   if( mEventData->mSelectionEnabled && (pStart || pEnd))
1122   {
1123     uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1124
1125     if (pStart)
1126     {
1127       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
1128     }
1129     if (pEnd)
1130     {
1131       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
1132     }
1133
1134     if (mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1135     {
1136       ChangeState( EventData::EDITING );
1137       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
1138       mEventData->mUpdateCursorPosition = true;
1139     }
1140     else
1141     {
1142       ChangeState( EventData::SELECTING );
1143       mEventData->mUpdateHighlightBox = true;
1144       mEventData->mUpdateLeftSelectionPosition = true;
1145       mEventData->mUpdateRightSelectionPosition = true;
1146     }
1147   }
1148 }
1149
1150 CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
1151 {
1152   if( nullptr == mEventData )
1153   {
1154     return 0;
1155   }
1156   return mEventData->mPrimaryCursorPosition;
1157 }
1158
1159 bool Controller::Impl::SetPrimaryCursorPosition( CharacterIndex index )
1160 {
1161   if( nullptr == mEventData )
1162   {
1163     // Nothing to do if there is no text.
1164     return false;
1165   }
1166
1167   if( mEventData->mPrimaryCursorPosition == index )
1168   {
1169     // Nothing for same cursor position.
1170     return false;
1171   }
1172
1173   uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1174   mEventData->mPrimaryCursorPosition = std::min(index, length);
1175   ChangeState( EventData::EDITING );
1176   mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1177   mEventData->mUpdateCursorPosition = true;
1178   ScrollTextToMatchCursor();
1179   return true;
1180 }
1181
1182 Uint32Pair Controller::Impl::GetTextSelectionRange() const
1183 {
1184   Uint32Pair range;
1185
1186   if( mEventData )
1187   {
1188     range.first = mEventData->mLeftSelectionPosition;
1189     range.second = mEventData->mRightSelectionPosition;
1190   }
1191
1192   return range;
1193 }
1194
1195 bool Controller::Impl::IsEditable() const
1196 {
1197   return mEventData && mEventData->mEditingEnabled;
1198 }
1199
1200 void Controller::Impl::SetEditable( bool editable )
1201 {
1202   if( mEventData)
1203   {
1204     mEventData->mEditingEnabled = editable;
1205   }
1206 }
1207
1208 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
1209 {
1210   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
1211   {
1212     // Nothing to select if handles are in the same place.
1213     selectedText.clear();
1214     return;
1215   }
1216
1217   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1218
1219   //Get start and end position of selection
1220   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1221   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
1222
1223   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
1224   const Length numberOfCharacters = utf32Characters.Count();
1225
1226   // Validate the start and end selection points
1227   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
1228   {
1229     //Get text as a UTF8 string
1230     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
1231
1232     if( deleteAfterRetrieval ) // Only delete text if copied successfully
1233     {
1234       // Keep a copy of the current input style.
1235       InputStyle currentInputStyle;
1236       currentInputStyle.Copy( mEventData->mInputStyle );
1237
1238       // Set as input style the style of the first deleted character.
1239       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
1240
1241       // Compare if the input style has changed.
1242       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
1243
1244       if( hasInputStyleChanged )
1245       {
1246         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
1247         // Queue the input style changed signal.
1248         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
1249       }
1250
1251       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
1252
1253       // Mark the paragraphs to be updated.
1254       if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
1255       {
1256         mTextUpdateInfo.mCharacterIndex = 0;
1257         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1258         mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
1259         mTextUpdateInfo.mClearAll = true;
1260       }
1261       else
1262       {
1263         mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1264         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1265       }
1266
1267       // Delete text between handles
1268       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1269       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1270       utf32Characters.Erase( first, last );
1271
1272       // Will show the cursor at the first character of the selection.
1273       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1274     }
1275     else
1276     {
1277       // Will show the cursor at the last character of the selection.
1278       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1279     }
1280
1281     mEventData->mDecoratorUpdated = true;
1282   }
1283 }
1284
1285 void Controller::Impl::SetSelection( int start, int end )
1286 {
1287   mEventData->mLeftSelectionPosition = start;
1288   mEventData->mRightSelectionPosition = end;
1289   mEventData->mUpdateCursorPosition = true;
1290 }
1291
1292 std::pair< int, int > Controller::Impl::GetSelectionIndexes() const
1293 {
1294   return { mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition };
1295 }
1296
1297 void Controller::Impl::ShowClipboard()
1298 {
1299   if( mClipboard )
1300   {
1301     mClipboard.ShowClipboard();
1302   }
1303 }
1304
1305 void Controller::Impl::HideClipboard()
1306 {
1307   if( mClipboard && mClipboardHideEnabled )
1308   {
1309     mClipboard.HideClipboard();
1310   }
1311 }
1312
1313 void Controller::Impl::SetClipboardHideEnable(bool enable)
1314 {
1315   mClipboardHideEnabled = enable;
1316 }
1317
1318 bool Controller::Impl::CopyStringToClipboard( const std::string& source )
1319 {
1320   //Send string to clipboard
1321   return ( mClipboard && mClipboard.SetItem( source ) );
1322 }
1323
1324 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
1325 {
1326   std::string selectedText;
1327   RetrieveSelection( selectedText, deleteAfterSending );
1328   CopyStringToClipboard( selectedText );
1329   ChangeState( EventData::EDITING );
1330 }
1331
1332 void Controller::Impl::RequestGetTextFromClipboard()
1333 {
1334   if ( mClipboard )
1335   {
1336     mClipboard.RequestItem();
1337   }
1338 }
1339
1340 void Controller::Impl::RepositionSelectionHandles()
1341 {
1342   SelectionHandleController::Reposition(*this);
1343 }
1344 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
1345 {
1346   SelectionHandleController::Reposition(*this, visualX, visualY, action);
1347 }
1348
1349 void Controller::Impl::SetPopupButtons()
1350 {
1351   /**
1352    *  Sets the Popup buttons to be shown depending on State.
1353    *
1354    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
1355    *
1356    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
1357    */
1358
1359   bool isEditable = IsEditable();
1360   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
1361
1362   if( EventData::SELECTING == mEventData->mState )
1363   {
1364     buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::COPY );
1365     if(isEditable)
1366     {
1367       buttonsToShow = TextSelectionPopup::Buttons( buttonsToShow | TextSelectionPopup::CUT );
1368     }
1369
1370     if( !IsClipboardEmpty() )
1371     {
1372       if(isEditable)
1373       {
1374         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1375       }
1376       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1377     }
1378
1379     if( !mEventData->mAllTextSelected )
1380     {
1381       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
1382     }
1383   }
1384   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
1385   {
1386     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
1387     {
1388       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
1389     }
1390
1391     if( !IsClipboardEmpty() )
1392     {
1393       if(isEditable)
1394       {
1395         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1396       }
1397       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1398     }
1399   }
1400   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
1401   {
1402     if ( !IsClipboardEmpty() )
1403     {
1404       if(isEditable)
1405       {
1406         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1407       }
1408       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1409     }
1410   }
1411
1412   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
1413 }
1414
1415 void Controller::Impl::ChangeState( EventData::State newState )
1416 {
1417   if( NULL == mEventData )
1418   {
1419     // Nothing to do if there is no text input.
1420     return;
1421   }
1422
1423   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
1424
1425   if( mEventData->mState != newState )
1426   {
1427     mEventData->mPreviousState = mEventData->mState;
1428     mEventData->mState = newState;
1429
1430     switch( mEventData->mState )
1431     {
1432       case EventData::INACTIVE:
1433       {
1434         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1435         mEventData->mDecorator->StopCursorBlink();
1436         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1437         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1438         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1439         mEventData->mDecorator->SetHighlightActive( false );
1440         mEventData->mDecorator->SetPopupActive( false );
1441         mEventData->mDecoratorUpdated = true;
1442         break;
1443       }
1444       case EventData::INTERRUPTED:
1445       {
1446         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1447         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1448         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1449         mEventData->mDecorator->SetHighlightActive( false );
1450         mEventData->mDecorator->SetPopupActive( false );
1451         mEventData->mDecoratorUpdated = true;
1452         break;
1453       }
1454       case EventData::SELECTING:
1455       {
1456         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1457         mEventData->mDecorator->StopCursorBlink();
1458         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1459         if ( mEventData->mGrabHandleEnabled )
1460         {
1461           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
1462           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
1463         }
1464         mEventData->mDecorator->SetHighlightActive( true );
1465         if( mEventData->mGrabHandlePopupEnabled )
1466         {
1467           SetPopupButtons();
1468           mEventData->mDecorator->SetPopupActive( true );
1469         }
1470         mEventData->mDecoratorUpdated = true;
1471         break;
1472       }
1473       case EventData::EDITING:
1474       {
1475         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1476         if( mEventData->mCursorBlinkEnabled )
1477         {
1478           mEventData->mDecorator->StartCursorBlink();
1479         }
1480         // Grab handle is not shown until a tap is received whilst EDITING
1481         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1482         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1483         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1484         mEventData->mDecorator->SetHighlightActive( false );
1485         if( mEventData->mGrabHandlePopupEnabled )
1486         {
1487           mEventData->mDecorator->SetPopupActive( false );
1488         }
1489         mEventData->mDecoratorUpdated = true;
1490         break;
1491       }
1492       case EventData::EDITING_WITH_POPUP:
1493       {
1494         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
1495
1496         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1497         if( mEventData->mCursorBlinkEnabled )
1498         {
1499           mEventData->mDecorator->StartCursorBlink();
1500         }
1501         if( mEventData->mSelectionEnabled )
1502         {
1503           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1504           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1505           mEventData->mDecorator->SetHighlightActive( false );
1506         }
1507         else if ( mEventData->mGrabHandleEnabled )
1508         {
1509           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1510         }
1511         if( mEventData->mGrabHandlePopupEnabled )
1512         {
1513           SetPopupButtons();
1514           mEventData->mDecorator->SetPopupActive( true );
1515         }
1516         mEventData->mDecoratorUpdated = true;
1517         break;
1518       }
1519       case EventData::EDITING_WITH_GRAB_HANDLE:
1520       {
1521         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
1522
1523         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1524         if( mEventData->mCursorBlinkEnabled )
1525         {
1526           mEventData->mDecorator->StartCursorBlink();
1527         }
1528         // Grab handle is not shown until a tap is received whilst EDITING
1529         if ( mEventData->mGrabHandleEnabled )
1530         {
1531           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1532         }
1533         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1534         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1535         mEventData->mDecorator->SetHighlightActive( false );
1536         if( mEventData->mGrabHandlePopupEnabled )
1537         {
1538           mEventData->mDecorator->SetPopupActive( false );
1539         }
1540         mEventData->mDecoratorUpdated = true;
1541         break;
1542       }
1543       case EventData::SELECTION_HANDLE_PANNING:
1544       {
1545         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1546         mEventData->mDecorator->StopCursorBlink();
1547         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1548         if ( mEventData->mGrabHandleEnabled )
1549         {
1550           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
1551           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
1552         }
1553         mEventData->mDecorator->SetHighlightActive( true );
1554         if( mEventData->mGrabHandlePopupEnabled )
1555         {
1556           mEventData->mDecorator->SetPopupActive( false );
1557         }
1558         mEventData->mDecoratorUpdated = true;
1559         break;
1560       }
1561       case EventData::GRAB_HANDLE_PANNING:
1562       {
1563         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
1564
1565         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1566         if( mEventData->mCursorBlinkEnabled )
1567         {
1568           mEventData->mDecorator->StartCursorBlink();
1569         }
1570         if ( mEventData->mGrabHandleEnabled )
1571         {
1572           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1573         }
1574         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1575         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1576         mEventData->mDecorator->SetHighlightActive( false );
1577         if( mEventData->mGrabHandlePopupEnabled )
1578         {
1579           mEventData->mDecorator->SetPopupActive( false );
1580         }
1581         mEventData->mDecoratorUpdated = true;
1582         break;
1583       }
1584       case EventData::EDITING_WITH_PASTE_POPUP:
1585       {
1586         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
1587
1588         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1589         if( mEventData->mCursorBlinkEnabled )
1590         {
1591           mEventData->mDecorator->StartCursorBlink();
1592         }
1593
1594         if ( mEventData->mGrabHandleEnabled )
1595         {
1596           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1597         }
1598         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1599         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1600         mEventData->mDecorator->SetHighlightActive( false );
1601
1602         if( mEventData->mGrabHandlePopupEnabled )
1603         {
1604           SetPopupButtons();
1605           mEventData->mDecorator->SetPopupActive( true );
1606         }
1607         mEventData->mDecoratorUpdated = true;
1608         break;
1609       }
1610       case EventData::TEXT_PANNING:
1611       {
1612         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1613         mEventData->mDecorator->StopCursorBlink();
1614         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1615         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
1616             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
1617         {
1618           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1619           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1620           mEventData->mDecorator->SetHighlightActive( true );
1621         }
1622
1623         if( mEventData->mGrabHandlePopupEnabled )
1624         {
1625           mEventData->mDecorator->SetPopupActive( false );
1626         }
1627
1628         mEventData->mDecoratorUpdated = true;
1629         break;
1630       }
1631     }
1632   }
1633 }
1634
1635 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
1636                                           CursorInfo& cursorInfo )
1637 {
1638   if( !IsShowingRealText() )
1639   {
1640     // Do not want to use the place-holder text to set the cursor position.
1641
1642     // Use the line's height of the font's family set to set the cursor's size.
1643     // If there is no font's family set, use the default font.
1644     // Use the current alignment to place the cursor at the beginning, center or end of the box.
1645
1646     cursorInfo.lineOffset = 0.f;
1647     cursorInfo.lineHeight = GetDefaultFontLineHeight();
1648     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
1649
1650     bool isRTL = false;
1651     if( mModel->mMatchSystemLanguageDirection )
1652     {
1653       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
1654     }
1655
1656     switch( mModel->mHorizontalAlignment )
1657     {
1658       case Text::HorizontalAlignment::BEGIN :
1659       {
1660         if( isRTL )
1661         {
1662           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1663         }
1664         else
1665         {
1666           cursorInfo.primaryPosition.x = 0.f;
1667         }
1668         break;
1669       }
1670       case Text::HorizontalAlignment::CENTER:
1671       {
1672         cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
1673         break;
1674       }
1675       case Text::HorizontalAlignment::END:
1676       {
1677         if( isRTL )
1678         {
1679           cursorInfo.primaryPosition.x = 0.f;
1680         }
1681         else
1682         {
1683           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1684         }
1685         break;
1686       }
1687     }
1688
1689     // Nothing else to do.
1690     return;
1691   }
1692
1693   const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
1694   GetCursorPositionParameters parameters;
1695   parameters.visualModel = mModel->mVisualModel;
1696   parameters.logicalModel = mModel->mLogicalModel;
1697   parameters.metrics = mMetrics;
1698   parameters.logical = logical;
1699   parameters.isMultiline = isMultiLine;
1700
1701   Text::GetCursorPosition( parameters,
1702                            cursorInfo );
1703
1704   // Adds Outline offset.
1705   const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
1706   cursorInfo.primaryPosition.x += outlineWidth;
1707   cursorInfo.primaryPosition.y += outlineWidth;
1708   cursorInfo.secondaryPosition.x += outlineWidth;
1709   cursorInfo.secondaryPosition.y += outlineWidth;
1710
1711   if( isMultiLine )
1712   {
1713     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
1714
1715     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
1716     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
1717
1718     if( 0.f > cursorInfo.primaryPosition.x )
1719     {
1720       cursorInfo.primaryPosition.x = 0.f;
1721     }
1722
1723     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
1724     if( cursorInfo.primaryPosition.x > edgeWidth )
1725     {
1726       cursorInfo.primaryPosition.x = edgeWidth;
1727     }
1728   }
1729 }
1730
1731 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
1732 {
1733   if( NULL == mEventData )
1734   {
1735     // Nothing to do if there is no text input.
1736     return 0u;
1737   }
1738
1739   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
1740
1741   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
1742   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1743
1744   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
1745   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
1746
1747   if( numberOfCharacters > 1u )
1748   {
1749     const Script script = mModel->mLogicalModel->GetScript( index );
1750     if( HasLigatureMustBreak( script ) )
1751     {
1752       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ, ...
1753       numberOfCharacters = 1u;
1754     }
1755   }
1756   else
1757   {
1758     while( 0u == numberOfCharacters )
1759     {
1760       ++glyphIndex;
1761       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
1762     }
1763   }
1764
1765   if( index < mEventData->mPrimaryCursorPosition )
1766   {
1767     cursorIndex -= numberOfCharacters;
1768   }
1769   else
1770   {
1771     cursorIndex += numberOfCharacters;
1772   }
1773
1774   // Will update the cursor hook position.
1775   mEventData->mUpdateCursorHookPosition = true;
1776
1777   return cursorIndex;
1778 }
1779
1780 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
1781 {
1782   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
1783   if( NULL == mEventData )
1784   {
1785     // Nothing to do if there is no text input.
1786     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
1787     return;
1788   }
1789
1790   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
1791
1792   mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
1793
1794   // Sets the cursor position.
1795   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
1796                                        cursorPosition.x,
1797                                        cursorPosition.y,
1798                                        cursorInfo.primaryCursorHeight,
1799                                        cursorInfo.lineHeight );
1800   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
1801
1802   if( mEventData->mUpdateGrabHandlePosition )
1803   {
1804     // Sets the grab handle position.
1805     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
1806                                          cursorPosition.x,
1807                                          cursorInfo.lineOffset + mModel->mScrollPosition.y,
1808                                          cursorInfo.lineHeight );
1809   }
1810
1811   if( cursorInfo.isSecondaryCursor )
1812   {
1813     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
1814                                          cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
1815                                          cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
1816                                          cursorInfo.secondaryCursorHeight,
1817                                          cursorInfo.lineHeight );
1818     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
1819   }
1820
1821   // Set which cursors are active according the state.
1822   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
1823   {
1824     if( cursorInfo.isSecondaryCursor )
1825     {
1826       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
1827     }
1828     else
1829     {
1830       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1831     }
1832   }
1833   else
1834   {
1835     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1836   }
1837
1838   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
1839 }
1840
1841 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
1842                                               const CursorInfo& cursorInfo )
1843 {
1844   SelectionHandleController::Update(*this, handleType, cursorInfo);
1845 }
1846
1847 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
1848 {
1849   // Clamp between -space & -alignment offset.
1850
1851   if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
1852   {
1853     const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
1854     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
1855     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
1856
1857     mEventData->mDecoratorUpdated = true;
1858   }
1859   else
1860   {
1861     mModel->mScrollPosition.x = 0.f;
1862   }
1863 }
1864
1865 void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
1866 {
1867   if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
1868   {
1869     // Nothing to do if the text is single line.
1870     return;
1871   }
1872
1873   // Clamp between -space & 0.
1874   if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
1875   {
1876     const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
1877     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
1878     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
1879
1880     mEventData->mDecoratorUpdated = true;
1881   }
1882   else
1883   {
1884     mModel->mScrollPosition.y = 0.f;
1885   }
1886 }
1887
1888 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
1889 {
1890   const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
1891
1892   // position is in actor's coords.
1893   const float positionEndX = position.x + cursorWidth;
1894   const float positionEndY = position.y + lineHeight;
1895
1896   // Transform the position to decorator coords.
1897   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
1898   const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
1899
1900   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
1901   const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
1902
1903   if( decoratorPositionBeginX < 0.f )
1904   {
1905     mModel->mScrollPosition.x = -position.x;
1906   }
1907   else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
1908   {
1909     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
1910   }
1911
1912   if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
1913   {
1914     if( decoratorPositionBeginY < 0.f )
1915     {
1916       mModel->mScrollPosition.y = -position.y;
1917     }
1918     else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
1919     {
1920       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
1921     }
1922   }
1923 }
1924
1925 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
1926 {
1927   // Get the current cursor position in decorator coords.
1928   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
1929
1930   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
1931
1932
1933
1934   // Calculate the offset to match the cursor position before the character was deleted.
1935   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
1936
1937   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
1938   if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
1939   {
1940     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
1941     mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
1942   }
1943
1944
1945   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
1946   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
1947
1948   // Makes the new cursor position visible if needed.
1949   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
1950 }
1951
1952 void Controller::Impl::ScrollTextToMatchCursor()
1953 {
1954   CursorInfo cursorInfo;
1955   GetCursorPosition( mEventData->mPrimaryCursorPosition, cursorInfo );
1956   ScrollTextToMatchCursor(cursorInfo);
1957 }
1958
1959 void Controller::Impl::RequestRelayout()
1960 {
1961   if( NULL != mControlInterface )
1962   {
1963     mControlInterface->RequestTextRelayout();
1964   }
1965 }
1966
1967 Actor Controller::Impl::CreateBackgroundActor()
1968 {
1969   // NOTE: Currently we only support background color for one line left-to-right text,
1970   //       so the following calculation is based on one line left-to-right text only!
1971
1972   Actor actor;
1973
1974   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
1975   if( numberOfGlyphs > 0u )
1976   {
1977     Vector<GlyphInfo> glyphs;
1978     glyphs.Resize( numberOfGlyphs );
1979
1980     Vector<Vector2> positions;
1981     positions.Resize( numberOfGlyphs );
1982
1983     // Get the line where the glyphs are laid-out.
1984     const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
1985     float alignmentOffset = lineRun->alignmentOffset;
1986     numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
1987                                       positions.Begin(),
1988                                       alignmentOffset,
1989                                       0u,
1990                                       numberOfGlyphs );
1991
1992     glyphs.Resize( numberOfGlyphs );
1993     positions.Resize( numberOfGlyphs );
1994
1995     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
1996     const Vector2* const positionsBuffer = positions.Begin();
1997
1998     BackgroundMesh mesh;
1999     mesh.mVertices.Reserve( 4u * glyphs.Size() );
2000     mesh.mIndices.Reserve( 6u * glyphs.Size() );
2001
2002     const Vector2 textSize = mView.GetLayoutSize();
2003
2004     const float offsetX = textSize.width * 0.5f;
2005     const float offsetY = textSize.height * 0.5f;
2006
2007     const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
2008     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
2009     const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
2010
2011     Vector4 quad;
2012     uint32_t numberOfQuads = 0u;
2013
2014     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
2015     {
2016       const GlyphInfo& glyph = *( glyphsBuffer + i );
2017
2018       // Get the background color of the character.
2019       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
2020       const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
2021       const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? defaultBackgroundColor : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
2022
2023       // Only create quads for glyphs with a background color
2024       if ( backgroundColor != Color::TRANSPARENT )
2025       {
2026         const Vector2 position = *( positionsBuffer + i );
2027
2028         if ( i == 0u && glyphSize == 1u ) // Only one glyph in the whole text
2029         {
2030           quad.x = position.x;
2031           quad.y = 0.0f;
2032           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
2033           quad.w = textSize.height;
2034         }
2035         else if ( i == 0u ) // The first glyph in the whole text
2036         {
2037           quad.x = position.x;
2038           quad.y = 0.0f;
2039           quad.z = quad.x - glyph.xBearing + glyph.advance;
2040           quad.w = textSize.height;
2041         }
2042         else if ( i == glyphSize - 1u ) // The last glyph in the whole text
2043         {
2044           quad.x = position.x - glyph.xBearing;
2045           quad.y = 0.0f;
2046           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
2047           quad.w = textSize.height;
2048         }
2049         else // The glyph in the middle of the text
2050         {
2051           quad.x = position.x - glyph.xBearing;
2052           quad.y = 0.0f;
2053           quad.z = quad.x + glyph.advance;
2054           quad.w = textSize.height;
2055         }
2056
2057         BackgroundVertex vertex;
2058
2059         // Top left
2060         vertex.mPosition.x = quad.x - offsetX;
2061         vertex.mPosition.y = quad.y - offsetY;
2062         vertex.mColor = backgroundColor;
2063         mesh.mVertices.PushBack( vertex );
2064
2065         // Top right
2066         vertex.mPosition.x = quad.z - offsetX;
2067         vertex.mPosition.y = quad.y - offsetY;
2068         vertex.mColor = backgroundColor;
2069         mesh.mVertices.PushBack( vertex );
2070
2071         // Bottom left
2072         vertex.mPosition.x = quad.x - offsetX;
2073         vertex.mPosition.y = quad.w - offsetY;
2074         vertex.mColor = backgroundColor;
2075         mesh.mVertices.PushBack( vertex );
2076
2077         // Bottom right
2078         vertex.mPosition.x = quad.z - offsetX;
2079         vertex.mPosition.y = quad.w - offsetY;
2080         vertex.mColor = backgroundColor;
2081         mesh.mVertices.PushBack( vertex );
2082
2083         // Six indices in counter clockwise winding
2084         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
2085         mesh.mIndices.PushBack( 0u + 4 * numberOfQuads );
2086         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
2087         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
2088         mesh.mIndices.PushBack( 3u + 4 * numberOfQuads );
2089         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
2090
2091         numberOfQuads++;
2092       }
2093     }
2094
2095     // Only create the background actor if there are glyphs with background color
2096     if ( mesh.mVertices.Count() > 0u )
2097     {
2098       Property::Map quadVertexFormat;
2099       quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
2100       quadVertexFormat[ "aColor" ] = Property::VECTOR4;
2101
2102       VertexBuffer quadVertices = VertexBuffer::New( quadVertexFormat );
2103       quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
2104
2105       Geometry quadGeometry = Geometry::New();
2106       quadGeometry.AddVertexBuffer( quadVertices );
2107       quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
2108
2109       if( !mShaderBackground )
2110       {
2111         mShaderBackground = Shader::New( VERTEX_SHADER_BACKGROUND, FRAGMENT_SHADER_BACKGROUND );
2112       }
2113
2114       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
2115       renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
2116       renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
2117
2118       actor = Actor::New();
2119       actor.SetProperty( Dali::Actor::Property::NAME, "TextBackgroundColorActor" );
2120       actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
2121       actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
2122       actor.SetProperty( Actor::Property::SIZE, textSize );
2123       actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR );
2124       actor.AddRenderer( renderer );
2125     }
2126   }
2127
2128   return actor;
2129 }
2130
2131 } // namespace Text
2132
2133 } // namespace Toolkit
2134
2135 } // namespace Dali