a26f5f5604969e4dbb455cedae3a41aa5265f5d3
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <iostream>
24 #include <dali/public-api/adaptor-framework/key.h>
25
26 // INTERNAL INCLUDES
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/layouts/layout-parameters.h>
30 #include <dali-toolkit/internal/text/multi-language-support.h>
31 #include <dali-toolkit/internal/text/script-run.h>
32 #include <dali-toolkit/internal/text/segmentation.h>
33 #include <dali-toolkit/internal/text/shaper.h>
34 #include <dali-toolkit/internal/text/text-controller-impl.h>
35 #include <dali-toolkit/internal/text/text-io.h>
36 #include <dali-toolkit/internal/text/text-view.h>
37
38 namespace
39 {
40
41 const float MAX_FLOAT = std::numeric_limits<float>::max();
42
43 const std::string EMPTY_STRING("");
44
45 } // namespace
46
47 namespace Dali
48 {
49
50 namespace Toolkit
51 {
52
53 namespace Text
54 {
55
56 ControllerPtr Controller::New( ControlInterface& controlInterface )
57 {
58   return ControllerPtr( new Controller( controlInterface ) );
59 }
60
61 void Controller::SetText( const std::string& text )
62 {
63   // Cancel previously queued inserts etc.
64   mImpl->mModifyEvents.clear();
65
66   // Remove the previously set text
67   ResetText();
68
69   if( ! text.empty() )
70   {
71     //  Convert text into UTF-32
72     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
73     utf32Characters.Resize( text.size() );
74
75     // This is a bit horrible but std::string returns a (signed) char*
76     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
77
78     // Transform a text array encoded in utf8 into an array encoded in utf32.
79     // It returns the actual number of characters.
80     Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
81     utf32Characters.Resize( characterCount );
82
83     // Reset the cursor position
84     if( mImpl->mEventData )
85     {
86       mImpl->mEventData->mPrimaryCursorPosition = characterCount;
87     }
88
89     // Update the rest of the model during size negotiation
90     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
91   }
92   else
93   {
94     mImpl->ShowPlaceholderText();
95   }
96
97   if( mImpl->mEventData )
98   {
99     // Cancel previously queued events
100     mImpl->mEventData->mEventQueue.clear();
101   }
102
103   // Reset keyboard as text changed
104   mImpl->PreEditReset();
105 }
106
107 void Controller::GetText( std::string& text ) const
108 {
109   if( ! mImpl->IsShowingPlaceholderText() )
110   {
111     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
112
113     if( 0u != utf32Characters.Count() )
114     {
115       uint32_t numberOfBytes = GetNumberOfUtf8Bytes( &utf32Characters[0], utf32Characters.Count() );
116
117       text.resize( numberOfBytes );
118
119       // This is a bit horrible but std::string returns a (signed) char*
120       Utf32ToUtf8( &utf32Characters[0], utf32Characters.Count(), reinterpret_cast<uint8_t*>(&text[0]) );
121     }
122   }
123 }
124
125 unsigned int Controller::GetLogicalCursorPosition() const
126 {
127   if( mImpl->mEventData )
128   {
129     return mImpl->mEventData->mPrimaryCursorPosition;
130   }
131
132   return 0u;
133 }
134
135 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
136 {
137   if( mImpl->mEventData )
138   {
139     if( PLACEHOLDER_TYPE_INACTIVE == type )
140     {
141       mImpl->mEventData->mPlaceholderTextInactive = text;
142     }
143     else
144     {
145       mImpl->mEventData->mPlaceholderTextActive = text;
146     }
147
148     mImpl->ShowPlaceholderText();
149   }
150 }
151
152 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
153 {
154   if( mImpl->mEventData )
155   {
156     if( PLACEHOLDER_TYPE_INACTIVE == type )
157     {
158       text = mImpl->mEventData->mPlaceholderTextInactive;
159     }
160     else
161     {
162       text = mImpl->mEventData->mPlaceholderTextActive;
163     }
164   }
165 }
166
167 void Controller::SetMaximumNumberOfCharacters( int maxCharacters )
168 {
169   if ( maxCharacters >= 0 )
170   {
171     mImpl->mMaximumNumberOfCharacters = maxCharacters;
172   }
173 }
174
175 int Controller::GetMaximumNumberOfCharacters()
176 {
177   return mImpl->mMaximumNumberOfCharacters;
178 }
179
180 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
181 {
182   if( !mImpl->mFontDefaults )
183   {
184     mImpl->mFontDefaults = new FontDefaults();
185   }
186
187   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
188   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
189   mImpl->mOperationsPending = ALL_OPERATIONS;
190   mImpl->mRecalculateNaturalSize = true;
191
192   // Clear the font-specific data
193   mImpl->mLogicalModel->mFontRuns.Clear();
194   mImpl->mVisualModel->mGlyphs.Clear();
195   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
196   mImpl->mVisualModel->mCharactersToGlyph.Clear();
197   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
198   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
199   mImpl->mVisualModel->mGlyphPositions.Clear();
200   mImpl->mVisualModel->mLines.Clear();
201   mImpl->mVisualModel->ClearCaches();
202
203   mImpl->RequestRelayout();
204 }
205
206 const std::string& Controller::GetDefaultFontFamily() const
207 {
208   if( mImpl->mFontDefaults )
209   {
210     return mImpl->mFontDefaults->mDefaultFontFamily;
211   }
212
213   return EMPTY_STRING;
214 }
215
216 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
217 {
218   if( !mImpl->mFontDefaults )
219   {
220     mImpl->mFontDefaults = new FontDefaults();
221   }
222
223   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
224   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
225   mImpl->mOperationsPending = ALL_OPERATIONS;
226   mImpl->mRecalculateNaturalSize = true;
227
228   // Clear the font-specific data
229   mImpl->mLogicalModel->mFontRuns.Clear();
230   mImpl->mVisualModel->mGlyphs.Clear();
231   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
232   mImpl->mVisualModel->mCharactersToGlyph.Clear();
233   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
234   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
235   mImpl->mVisualModel->mGlyphPositions.Clear();
236   mImpl->mVisualModel->mLines.Clear();
237   mImpl->mVisualModel->ClearCaches();
238
239   mImpl->RequestRelayout();
240 }
241
242 const std::string& Controller::GetDefaultFontStyle() const
243 {
244   if( mImpl->mFontDefaults )
245   {
246     return mImpl->mFontDefaults->mDefaultFontStyle;
247   }
248
249   return EMPTY_STRING;
250 }
251
252 void Controller::SetDefaultPointSize( float pointSize )
253 {
254   if( !mImpl->mFontDefaults )
255   {
256     mImpl->mFontDefaults = new FontDefaults();
257   }
258
259   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
260   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
261   mImpl->mOperationsPending = ALL_OPERATIONS;
262   mImpl->mRecalculateNaturalSize = true;
263
264   // Clear the font-specific data
265   mImpl->mLogicalModel->mFontRuns.Clear();
266   mImpl->mVisualModel->mGlyphs.Clear();
267   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
268   mImpl->mVisualModel->mCharactersToGlyph.Clear();
269   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
270   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
271   mImpl->mVisualModel->mGlyphPositions.Clear();
272   mImpl->mVisualModel->mLines.Clear();
273   mImpl->mVisualModel->ClearCaches();
274
275   mImpl->RequestRelayout();
276 }
277
278 float Controller::GetDefaultPointSize() const
279 {
280   if( mImpl->mFontDefaults )
281   {
282     return mImpl->mFontDefaults->mDefaultPointSize;
283   }
284
285   return 0.0f;
286 }
287
288 void Controller::SetTextColor( const Vector4& textColor )
289 {
290   mImpl->mTextColor = textColor;
291
292   if( ! mImpl->IsShowingPlaceholderText() )
293   {
294     mImpl->mVisualModel->SetTextColor( textColor );
295   }
296 }
297
298 const Vector4& Controller::GetTextColor() const
299 {
300   return mImpl->mTextColor;
301 }
302
303 bool Controller::RemoveText( int cursorOffset, int numberOfChars )
304 {
305   bool removed( false );
306
307   if( ! mImpl->IsShowingPlaceholderText() )
308   {
309     // Delete at current cursor position
310     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
311     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
312
313     CharacterIndex cursorIndex = oldCursorIndex;
314
315     // Validate the cursor position & number of characters
316     if( std::abs( cursorOffset ) <= cursorIndex )
317     {
318       cursorIndex = oldCursorIndex + cursorOffset;
319     }
320
321     if( (cursorIndex + numberOfChars) > currentText.Count() )
322     {
323       numberOfChars = currentText.Count() - cursorIndex;
324     }
325
326     if( cursorIndex >= 0 &&
327         (cursorIndex + numberOfChars) <= currentText.Count() )
328     {
329       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
330       Vector<Character>::Iterator last  = first + numberOfChars;
331
332       currentText.Erase( first, last );
333
334       // Cursor position retreat
335       oldCursorIndex = cursorIndex;
336
337       removed = true;
338     }
339   }
340
341   return removed;
342 }
343
344 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
345 {
346   if( mImpl->mEventData )
347   {
348     mImpl->mEventData->mPlaceholderTextColor = textColor;
349   }
350
351   if( mImpl->IsShowingPlaceholderText() )
352   {
353     mImpl->mVisualModel->SetTextColor( textColor );
354   }
355 }
356
357 const Vector4& Controller::GetPlaceholderTextColor() const
358 {
359   if( mImpl->mEventData )
360   {
361     return mImpl->mEventData->mPlaceholderTextColor;
362   }
363
364   return Color::BLACK;
365 }
366
367 void Controller::SetShadowOffset( const Vector2& shadowOffset )
368 {
369   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
370 }
371
372 const Vector2& Controller::GetShadowOffset() const
373 {
374   return mImpl->mVisualModel->GetShadowOffset();
375 }
376
377 void Controller::SetShadowColor( const Vector4& shadowColor )
378 {
379   mImpl->mVisualModel->SetShadowColor( shadowColor );
380 }
381
382 const Vector4& Controller::GetShadowColor() const
383 {
384   return mImpl->mVisualModel->GetShadowColor();
385 }
386
387 void Controller::SetUnderlineColor( const Vector4& color )
388 {
389   mImpl->mVisualModel->SetUnderlineColor( color );
390 }
391
392 const Vector4& Controller::GetUnderlineColor() const
393 {
394   return mImpl->mVisualModel->GetUnderlineColor();
395 }
396
397 void Controller::SetUnderlineEnabled( bool enabled )
398 {
399   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
400 }
401
402 bool Controller::IsUnderlineEnabled() const
403 {
404   return mImpl->mVisualModel->IsUnderlineEnabled();
405 }
406
407 void Controller::SetUnderlineHeight( float height )
408 {
409   mImpl->mVisualModel->SetUnderlineHeight( height );
410 }
411
412 float Controller::GetUnderlineHeight() const
413 {
414   return mImpl->mVisualModel->GetUnderlineHeight();
415 }
416
417 void Controller::EnableTextInput( DecoratorPtr decorator )
418 {
419   if( !mImpl->mEventData )
420   {
421     mImpl->mEventData = new EventData( decorator );
422   }
423 }
424
425 void Controller::SetEnableCursorBlink( bool enable )
426 {
427   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
428
429   if( mImpl->mEventData )
430   {
431     mImpl->mEventData->mCursorBlinkEnabled = enable;
432
433     if( !enable &&
434         mImpl->mEventData->mDecorator )
435     {
436       mImpl->mEventData->mDecorator->StopCursorBlink();
437     }
438   }
439 }
440
441 bool Controller::GetEnableCursorBlink() const
442 {
443   if( mImpl->mEventData )
444   {
445     return mImpl->mEventData->mCursorBlinkEnabled;
446   }
447
448   return false;
449 }
450
451 const Vector2& Controller::GetScrollPosition() const
452 {
453   if( mImpl->mEventData )
454   {
455     return mImpl->mEventData->mScrollPosition;
456   }
457
458   return Vector2::ZERO;
459 }
460
461 const Vector2& Controller::GetAlignmentOffset() const
462 {
463   return mImpl->mAlignmentOffset;
464 }
465
466 Vector3 Controller::GetNaturalSize()
467 {
468   Vector3 naturalSize;
469
470   // Make sure the model is up-to-date before layouting
471   ProcessModifyEvents();
472
473   if( mImpl->mRecalculateNaturalSize )
474   {
475     // Operations that can be done only once until the text changes.
476     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
477                                                                            GET_SCRIPTS       |
478                                                                            VALIDATE_FONTS    |
479                                                                            GET_LINE_BREAKS   |
480                                                                            GET_WORD_BREAKS   |
481                                                                            BIDI_INFO         |
482                                                                            SHAPE_TEXT        |
483                                                                            GET_GLYPH_METRICS );
484     // Make sure the model is up-to-date before layouting
485     mImpl->UpdateModel( onlyOnceOperations );
486
487     // Operations that need to be done if the size changes.
488     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
489                                                                         ALIGN  |
490                                                                         REORDER );
491
492     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
493                 static_cast<OperationsMask>( onlyOnceOperations |
494                                              sizeOperations ),
495                 naturalSize.GetVectorXY() );
496
497     // Do not do again the only once operations.
498     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
499
500     // Do the size related operations again.
501     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
502
503     // Stores the natural size to avoid recalculate it again
504     // unless the text/style changes.
505     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
506
507     mImpl->mRecalculateNaturalSize = false;
508   }
509   else
510   {
511     naturalSize = mImpl->mVisualModel->GetNaturalSize();
512   }
513
514   return naturalSize;
515 }
516
517 float Controller::GetHeightForWidth( float width )
518 {
519   // Make sure the model is up-to-date before layouting
520   ProcessModifyEvents();
521
522   Size layoutSize;
523   if( width != mImpl->mControlSize.width )
524   {
525     // Operations that can be done only once until the text changes.
526     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
527                                                                            GET_SCRIPTS       |
528                                                                            VALIDATE_FONTS    |
529                                                                            GET_LINE_BREAKS   |
530                                                                            GET_WORD_BREAKS   |
531                                                                            BIDI_INFO         |
532                                                                            SHAPE_TEXT        |
533                                                                            GET_GLYPH_METRICS );
534     // Make sure the model is up-to-date before layouting
535     mImpl->UpdateModel( onlyOnceOperations );
536
537     // Operations that need to be done if the size changes.
538     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
539                                                                         ALIGN  |
540                                                                         REORDER );
541
542     DoRelayout( Size( width, MAX_FLOAT ),
543                 static_cast<OperationsMask>( onlyOnceOperations |
544                                              sizeOperations ),
545                 layoutSize );
546
547     // Do not do again the only once operations.
548     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
549
550     // Do the size related operations again.
551     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
552   }
553   else
554   {
555     layoutSize = mImpl->mVisualModel->GetActualSize();
556   }
557
558   return layoutSize.height;
559 }
560
561 bool Controller::Relayout( const Size& size )
562 {
563   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
564   {
565     bool glyphsRemoved( false );
566     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
567     {
568       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
569       glyphsRemoved = true;
570     }
571     // Not worth to relayout if width or height is equal to zero.
572     return glyphsRemoved;
573   }
574
575   if( size != mImpl->mControlSize )
576   {
577     // Operations that need to be done if the size changes.
578     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
579                                                              LAYOUT                    |
580                                                              ALIGN                     |
581                                                              UPDATE_ACTUAL_SIZE        |
582                                                              REORDER );
583
584     mImpl->mControlSize = size;
585   }
586
587   // Make sure the model is up-to-date before layouting
588   ProcessModifyEvents();
589   mImpl->UpdateModel( mImpl->mOperationsPending );
590
591   Size layoutSize;
592   bool updated = DoRelayout( mImpl->mControlSize,
593                              mImpl->mOperationsPending,
594                              layoutSize );
595
596   // Do not re-do any operation until something changes.
597   mImpl->mOperationsPending = NO_OPERATION;
598
599   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
600   CalculateTextAlignment( size );
601
602   if( mImpl->mEventData )
603   {
604     // Move the cursor, grab handle etc.
605     updated = mImpl->ProcessInputEvents() || updated;
606   }
607
608   return updated;
609 }
610
611 void Controller::ProcessModifyEvents()
612 {
613   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
614
615   for( unsigned int i=0; i<events.size(); ++i )
616   {
617     if( ModifyEvent::PLACEHOLDER_TEXT == events[0].type )
618     {
619       // Use placeholder if text is empty
620       if( 0u == mImpl->mLogicalModel->mText.Count() &&
621           mImpl->IsShowingPlaceholderText() )
622       {
623         mImpl->ReplaceTextWithPlaceholder();
624       }
625     }
626     else if( ModifyEvent::TEXT_REPLACED == events[0].type )
627     {
628       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
629       DALI_ASSERT_DEBUG( 0 == i && "Unexpected TEXT_REPLACED event" );
630
631       TextReplacedEvent();
632     }
633     else if( ModifyEvent::TEXT_INSERTED == events[0].type )
634     {
635       TextInsertedEvent();
636     }
637     else if( ModifyEvent::TEXT_DELETED == events[0].type )
638     {
639       // Placeholder-text cannot be deleted
640       if( !mImpl->IsShowingPlaceholderText() )
641       {
642         TextDeletedEvent();
643       }
644     }
645   }
646
647   // Discard temporary text
648   events.clear();
649 }
650
651 void Controller::ResetText()
652 {
653   // Reset buffers.
654   mImpl->mLogicalModel->mText.Clear();
655   mImpl->mLogicalModel->mScriptRuns.Clear();
656   mImpl->mLogicalModel->mFontRuns.Clear();
657   mImpl->mLogicalModel->mLineBreakInfo.Clear();
658   mImpl->mLogicalModel->mWordBreakInfo.Clear();
659   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
660   mImpl->mLogicalModel->mCharacterDirections.Clear();
661   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
662   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
663   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
664   mImpl->mVisualModel->mGlyphs.Clear();
665   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
666   mImpl->mVisualModel->mCharactersToGlyph.Clear();
667   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
668   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
669   mImpl->mVisualModel->mGlyphPositions.Clear();
670   mImpl->mVisualModel->mLines.Clear();
671   mImpl->mVisualModel->ClearCaches();
672
673   // Reset the cursor position
674   if( mImpl->mEventData )
675   {
676     mImpl->mEventData->mPrimaryCursorPosition = 0;
677   }
678
679   // We have cleared everything including the placeholder-text
680   mImpl->PlaceholderCleared();
681
682   // The natural size needs to be re-calculated.
683   mImpl->mRecalculateNaturalSize = true;
684
685   // Apply modifications to the model
686   mImpl->mOperationsPending = ALL_OPERATIONS;
687 }
688
689 void Controller::TextReplacedEvent()
690 {
691   // Reset buffers.
692   mImpl->mLogicalModel->mScriptRuns.Clear();
693   mImpl->mLogicalModel->mFontRuns.Clear();
694   mImpl->mLogicalModel->mLineBreakInfo.Clear();
695   mImpl->mLogicalModel->mWordBreakInfo.Clear();
696   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
697   mImpl->mLogicalModel->mCharacterDirections.Clear();
698   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
699   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
700   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
701   mImpl->mVisualModel->mGlyphs.Clear();
702   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
703   mImpl->mVisualModel->mCharactersToGlyph.Clear();
704   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
705   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
706   mImpl->mVisualModel->mGlyphPositions.Clear();
707   mImpl->mVisualModel->mLines.Clear();
708   mImpl->mVisualModel->ClearCaches();
709
710   // The natural size needs to be re-calculated.
711   mImpl->mRecalculateNaturalSize = true;
712
713   // Apply modifications to the model
714   mImpl->mOperationsPending = ALL_OPERATIONS;
715   mImpl->UpdateModel( ALL_OPERATIONS );
716   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
717                                                            ALIGN              |
718                                                            UPDATE_ACTUAL_SIZE |
719                                                            REORDER );
720 }
721
722 void Controller::TextInsertedEvent()
723 {
724   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
725
726   // TODO - Optimize this
727   mImpl->mLogicalModel->mScriptRuns.Clear();
728   mImpl->mLogicalModel->mFontRuns.Clear();
729   mImpl->mLogicalModel->mLineBreakInfo.Clear();
730   mImpl->mLogicalModel->mWordBreakInfo.Clear();
731   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
732   mImpl->mLogicalModel->mCharacterDirections.Clear();
733   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
734   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
735   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
736   mImpl->mVisualModel->mGlyphs.Clear();
737   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
738   mImpl->mVisualModel->mCharactersToGlyph.Clear();
739   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
740   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
741   mImpl->mVisualModel->mGlyphPositions.Clear();
742   mImpl->mVisualModel->mLines.Clear();
743   mImpl->mVisualModel->ClearCaches();
744
745   // The natural size needs to be re-calculated.
746   mImpl->mRecalculateNaturalSize = true;
747
748   // Apply modifications to the model; TODO - Optimize this
749   mImpl->mOperationsPending = ALL_OPERATIONS;
750   mImpl->UpdateModel( ALL_OPERATIONS );
751   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
752                                                            ALIGN              |
753                                                            UPDATE_ACTUAL_SIZE |
754                                                            REORDER );
755
756   // Queue a cursor reposition event; this must wait until after DoRelayout()
757   mImpl->mEventData->mUpdateCursorPosition = true;
758   mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
759 }
760
761 void Controller::TextDeletedEvent()
762 {
763   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
764
765   // TODO - Optimize this
766   mImpl->mLogicalModel->mScriptRuns.Clear();
767   mImpl->mLogicalModel->mFontRuns.Clear();
768   mImpl->mLogicalModel->mLineBreakInfo.Clear();
769   mImpl->mLogicalModel->mWordBreakInfo.Clear();
770   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
771   mImpl->mLogicalModel->mCharacterDirections.Clear();
772   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
773   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
774   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
775   mImpl->mVisualModel->mGlyphs.Clear();
776   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
777   mImpl->mVisualModel->mCharactersToGlyph.Clear();
778   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
779   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
780   mImpl->mVisualModel->mGlyphPositions.Clear();
781   mImpl->mVisualModel->mLines.Clear();
782   mImpl->mVisualModel->ClearCaches();
783
784   // The natural size needs to be re-calculated.
785   mImpl->mRecalculateNaturalSize = true;
786
787   // Apply modifications to the model; TODO - Optimize this
788   mImpl->mOperationsPending = ALL_OPERATIONS;
789   mImpl->UpdateModel( ALL_OPERATIONS );
790   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
791                                                            ALIGN              |
792                                                            UPDATE_ACTUAL_SIZE |
793                                                            REORDER );
794
795   // Queue a cursor reposition event; this must wait until after DoRelayout()
796   mImpl->mEventData->mUpdateCursorPosition = true;
797   mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
798 }
799
800 bool Controller::DoRelayout( const Size& size,
801                              OperationsMask operationsRequired,
802                              Size& layoutSize )
803 {
804   bool viewUpdated( false );
805
806   // Calculate the operations to be done.
807   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
808
809   if( LAYOUT & operations )
810   {
811     // Some vectors with data needed to layout and reorder may be void
812     // after the first time the text has been laid out.
813     // Fill the vectors again.
814
815     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
816
817     if( 0u == numberOfGlyphs )
818     {
819       // Nothing else to do if there is no glyphs.
820       return true;
821     }
822
823     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
824     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
825     Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
826     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
827     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
828     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
829
830     // Set the layout parameters.
831     LayoutParameters layoutParameters( size,
832                                        mImpl->mLogicalModel->mText.Begin(),
833                                        lineBreakInfo.Begin(),
834                                        wordBreakInfo.Begin(),
835                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
836                                        numberOfGlyphs,
837                                        glyphs.Begin(),
838                                        glyphsToCharactersMap.Begin(),
839                                        charactersPerGlyph.Begin() );
840
841     // The laid-out lines.
842     // It's not possible to know in how many lines the text is going to be laid-out,
843     // but it can be resized at least with the number of 'paragraphs' to avoid
844     // some re-allocations.
845     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
846
847     // Delete any previous laid out lines before setting the new ones.
848     lines.Clear();
849
850     // The capacity of the bidirectional paragraph info is the number of paragraphs.
851     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
852
853     // Resize the vector of positions to have the same size than the vector of glyphs.
854     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
855     glyphPositions.Resize( numberOfGlyphs );
856
857     // Update the visual model.
858     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
859                                                    glyphPositions,
860                                                    lines,
861                                                    layoutSize );
862
863     if( viewUpdated )
864     {
865       // Reorder the lines
866       if( REORDER & operations )
867       {
868         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
869
870         // Check first if there are paragraphs with bidirectional info.
871         if( 0u != bidirectionalInfo.Count() )
872         {
873           // Get the lines
874           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
875
876           // Reorder the lines.
877           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
878           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
879           ReorderLines( bidirectionalInfo,
880                         lines,
881                         lineBidirectionalInfoRuns );
882
883           // Set the bidirectional info into the model.
884           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
885           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
886                                                        numberOfBidirectionalInfoRuns );
887
888           // Set the bidirectional info per line into the layout parameters.
889           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
890           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
891
892           // Get the character to glyph conversion table and set into the layout.
893           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
894
895           // Get the glyphs per character table and set into the layout.
896           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
897
898           // Re-layout the text. Reorder those lines with right to left characters.
899           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
900                                                          glyphPositions );
901
902           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
903           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
904                  endIt = lineBidirectionalInfoRuns.End();
905                it != endIt;
906                ++it )
907           {
908             BidirectionalLineInfoRun& bidiLineInfo = *it;
909
910             free( bidiLineInfo.visualToLogicalMap );
911           }
912         }
913       } // REORDER
914
915       if( ALIGN & operations )
916       {
917         mImpl->mLayoutEngine.Align( layoutParameters,
918                                     layoutSize,
919                                     lines,
920                                     glyphPositions );
921       }
922
923       // Sets the actual size.
924       if( UPDATE_ACTUAL_SIZE & operations )
925       {
926         mImpl->mVisualModel->SetActualSize( layoutSize );
927       }
928     } // view updated
929   }
930   else
931   {
932     layoutSize = mImpl->mVisualModel->GetActualSize();
933   }
934
935   return viewUpdated;
936 }
937
938 void Controller::CalculateTextAlignment( const Size& size )
939 {
940   // Get the direction of the first character.
941   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
942
943   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
944
945   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
946   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
947   if( firstParagraphDirection &&
948       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
949   {
950     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
951     {
952       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
953     }
954     else
955     {
956       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
957     }
958   }
959
960   switch( horizontalAlignment )
961   {
962     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
963     {
964       mImpl->mAlignmentOffset.x = 0.f;
965       break;
966     }
967     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
968     {
969       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
970       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
971       break;
972     }
973     case LayoutEngine::HORIZONTAL_ALIGN_END:
974     {
975       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
976       break;
977     }
978   }
979
980   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
981   switch( verticalAlignment )
982   {
983     case LayoutEngine::VERTICAL_ALIGN_TOP:
984     {
985       mImpl->mAlignmentOffset.y = 0.f;
986       break;
987     }
988     case LayoutEngine::VERTICAL_ALIGN_CENTER:
989     {
990       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
991       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
992       break;
993     }
994     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
995     {
996       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
997       break;
998     }
999   }
1000 }
1001
1002 LayoutEngine& Controller::GetLayoutEngine()
1003 {
1004   return mImpl->mLayoutEngine;
1005 }
1006
1007 View& Controller::GetView()
1008 {
1009   return mImpl->mView;
1010 }
1011
1012 void Controller::KeyboardFocusGainEvent()
1013 {
1014   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1015
1016   if( mImpl->mEventData )
1017   {
1018     Event event( Event::KEYBOARD_FOCUS_GAIN_EVENT );
1019     mImpl->mEventData->mEventQueue.push_back( event );
1020
1021     mImpl->RequestRelayout();
1022   }
1023 }
1024
1025 void Controller::KeyboardFocusLostEvent()
1026 {
1027   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1028
1029   if( mImpl->mEventData )
1030   {
1031     Event event( Event::KEYBOARD_FOCUS_LOST_EVENT );
1032     mImpl->mEventData->mEventQueue.push_back( event );
1033
1034     mImpl->RequestRelayout();
1035   }
1036 }
1037
1038 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1039 {
1040   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1041
1042   if( mImpl->mEventData &&
1043       keyEvent.state == KeyEvent::Down )
1044   {
1045     int keyCode = keyEvent.keyCode;
1046     const std::string& keyString = keyEvent.keyPressed;
1047
1048     // Pre-process to separate modifying events from non-modifying input events.
1049     if( Dali::DALI_KEY_ESCAPE == keyCode )
1050     {
1051       // Escape key is a special case which causes focus loss
1052       KeyboardFocusLostEvent();
1053     }
1054     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1055              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1056              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1057              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1058     {
1059       Event event( Event::CURSOR_KEY_EVENT );
1060       event.p1.mInt = keyCode;
1061       mImpl->mEventData->mEventQueue.push_back( event );
1062     }
1063     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1064     {
1065       // Remove the character before the current cursor position
1066       bool removed = RemoveText( -1, 1 );
1067
1068       if( removed )
1069       {
1070         if( 0u == mImpl->mLogicalModel->mText.Count() )
1071         {
1072           mImpl->ShowPlaceholderText();
1073         }
1074         else
1075         {
1076           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1077         }
1078       }
1079     }
1080     else
1081     {
1082       InsertText( keyString, COMMIT );
1083     }
1084
1085     mImpl->ChangeState( EventData::EDITING ); // todo Confirm this is the best place to change the state of
1086
1087     mImpl->RequestRelayout();
1088   }
1089
1090   return false;
1091 }
1092
1093 void Controller::InsertText( const std::string& text, Controller::InsertType type )
1094 {
1095   bool removedPreEdit( false );
1096   bool maxLengthReached( false );
1097
1098   if( ! text.empty() )
1099   {
1100     if( mImpl->IsShowingPlaceholderText() )
1101     {
1102       ResetText();
1103     }
1104   }
1105
1106   if( mImpl->mEventData )
1107   {
1108     if( COMMIT == type )
1109     {
1110       mImpl->mEventData->mPreEditFlag = false;
1111     }
1112     else // PRE_EDIT
1113     {
1114       if( mImpl->mEventData->mPreEditFlag &&
1115           0 != mImpl->mEventData->mPreEditLength )
1116       {
1117         // Remove previous pre-edit text
1118         mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
1119         removedPreEdit = RemoveText( -1, mImpl->mEventData->mPreEditLength );
1120       }
1121       else
1122       {
1123         // Record the start of the pre-edit text
1124         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
1125         mImpl->mEventData->mPreEditLength = text.size();
1126       }
1127
1128       mImpl->mEventData->mPreEditFlag = true;
1129     }
1130   }
1131
1132   if( ! text.empty() )
1133   {
1134     //  Convert text into UTF-32
1135     Vector<Character> utf32Characters;
1136     utf32Characters.Resize( text.size() );
1137
1138     // This is a bit horrible but std::string returns a (signed) char*
1139     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1140
1141     // Transform a text array encoded in utf8 into an array encoded in utf32.
1142     // It returns the actual number of characters.
1143     Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1144     utf32Characters.Resize( characterCount );
1145
1146     const Length numberOfCharactersInModel = mImpl->mLogicalModel->GetNumberOfCharacters();
1147
1148     // Restrict new text to fit within Maximum characters setting
1149     Length maxSizeOfNewText = std::min ( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
1150     maxLengthReached = ( characterCount > maxSizeOfNewText );
1151
1152     // Insert at current cursor position
1153     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
1154
1155     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1156
1157     if( cursorIndex < numberOfCharactersInModel )
1158     {
1159       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1160     }
1161     else
1162     {
1163       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1164     }
1165
1166     cursorIndex += maxSizeOfNewText;
1167   }
1168
1169   if( removedPreEdit || !text.empty() )
1170   {
1171     // Queue an inserted event
1172     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
1173   }
1174
1175   if( maxLengthReached )
1176   {
1177     mImpl->mControlInterface.MaxLengthReached();
1178
1179     mImpl->PreEditReset();
1180   }
1181 }
1182
1183 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1184 {
1185   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1186
1187   if( mImpl->mEventData )
1188   {
1189     Event event( Event::TAP_EVENT );
1190     event.p1.mUint = tapCount;
1191     event.p2.mFloat = x;
1192     event.p3.mFloat = y;
1193     mImpl->mEventData->mEventQueue.push_back( event );
1194
1195     mImpl->RequestRelayout();
1196   }
1197
1198   // Reset keyboard as tap event has occurred.
1199   mImpl->PreEditReset();
1200 }
1201
1202 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1203 {
1204   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1205
1206   if( mImpl->mEventData )
1207   {
1208     Event event( Event::PAN_EVENT );
1209     event.p1.mInt = state;
1210     event.p2.mFloat = displacement.x;
1211     event.p3.mFloat = displacement.y;
1212     mImpl->mEventData->mEventQueue.push_back( event );
1213
1214     mImpl->RequestRelayout();
1215   }
1216 }
1217
1218 void Controller::HandleEvent( HandleType handleType, HandleState state, float x, float y )
1219 {
1220   DALI_ASSERT_DEBUG( mImpl->mEventData && "Controller::HandleEvent. Unexpected HandleEvent" );
1221
1222   if( mImpl->mEventData )
1223   {
1224     switch( handleType )
1225     {
1226       case GRAB_HANDLE:
1227       {
1228         Event event( Event::GRAB_HANDLE_EVENT );
1229         event.p1.mUint  = state;
1230         event.p2.mFloat = x;
1231         event.p3.mFloat = y;
1232
1233         mImpl->mEventData->mEventQueue.push_back( event );
1234         break;
1235       }
1236       case LEFT_SELECTION_HANDLE:
1237       {
1238         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
1239         event.p1.mUint  = state;
1240         event.p2.mFloat = x;
1241         event.p3.mFloat = y;
1242
1243         mImpl->mEventData->mEventQueue.push_back( event );
1244         break;
1245       }
1246       case RIGHT_SELECTION_HANDLE:
1247       {
1248         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
1249         event.p1.mUint  = state;
1250         event.p2.mFloat = x;
1251         event.p3.mFloat = y;
1252
1253         mImpl->mEventData->mEventQueue.push_back( event );
1254         break;
1255       }
1256       case HANDLE_TYPE_COUNT:
1257       {
1258         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
1259       }
1260     }
1261
1262     mImpl->RequestRelayout();
1263   }
1264 }
1265
1266 Controller::~Controller()
1267 {
1268   delete mImpl;
1269 }
1270
1271 Controller::Controller( ControlInterface& controlInterface )
1272 : mImpl( NULL )
1273 {
1274   mImpl = new Controller::Impl( controlInterface );
1275 }
1276
1277 } // namespace Text
1278
1279 } // namespace Toolkit
1280
1281 } // namespace Dali