2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/text/text-controller.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/public-api/text-abstraction/font-client.h>
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/logical-model.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/script-run.h>
35 #include <dali-toolkit/internal/text/segmentation.h>
36 #include <dali-toolkit/internal/text/shaper.h>
37 #include <dali-toolkit/internal/text/text-view.h>
38 #include <dali-toolkit/internal/text/visual-model.h>
44 const float MAX_FLOAT = std::numeric_limits<float>::max();
45 const std::string EMPTY_STRING;
57 struct Controller::TextInput
59 // Used to queue input events until DoRelayout()
62 KEYBOARD_FOCUS_GAIN_EVENT,
63 KEYBOARD_FOCUS_LOST_EVENT,
79 Event( EventType eventType )
99 TextInput( LogicalModelPtr logicalModel,
100 VisualModelPtr visualModel,
101 DecoratorPtr decorator )
102 : mLogicalModel( logicalModel ),
103 mVisualModel( visualModel ),
104 mDecorator( decorator ),
106 mDecoratorUpdated( false ),
107 mCursorBlinkEnabled( true )
112 * @brief Helper to move the cursor, grab handle etc.
114 bool ProcessInputEvents()
116 mDecoratorUpdated = false;
120 for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
124 case KEYBOARD_FOCUS_GAIN_EVENT:
126 OnKeyboardFocus( true );
129 case KEYBOARD_FOCUS_LOST_EVENT:
131 OnKeyboardFocus( false );
144 case GRAB_HANDLE_EVENT:
146 OnGrabHandleEvent( *iter );
155 return mDecoratorUpdated;
158 void OnKeyboardFocus( bool hasFocus )
162 ChangeState( INACTIVE );
166 ChangeState( EDITING );
170 void OnKeyEvent( const Event& event )
172 int keyCode = event.p1.mInt;
174 // Handle state changes
175 if( Dali::DALI_KEY_ESCAPE == keyCode )
177 ChangeState( INACTIVE ); // Escape key ends edit mode
179 else if ( event.p2.mString )
181 // Some text may be selected, hiding keyboard causes an empty keystring to be sent, we don't want to delete highlight in this case
182 ChangeState( EDITING );
185 // Handle the actual key event
186 if( Dali::DALI_KEY_BACKSPACE == keyCode )
188 HandleBackspaceKey();
190 else if( Dali::DALI_KEY_CURSOR_LEFT == keyCode ||
191 Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
192 Dali::DALI_KEY_CURSOR_UP == keyCode ||
193 Dali::DALI_KEY_CURSOR_DOWN == keyCode )
195 HandleCursorKey( keyCode );
197 else if ( event.p2.mString )
199 HandleKeyString( event.p2.mString );
201 delete [] event.p2.mString;
205 void HandleBackspaceKey()
210 void HandleCursorKey( int keyCode )
215 void HandleKeyString( const char* keyString )
220 void OnTapEvent( const Event& event )
222 unsigned int tapCount = event.p1.mUint;
226 ChangeState( EDITING );
228 float xPosition = event.p2.mFloat;
229 float yPosition = event.p3.mFloat;
231 GetClosestCursorPosition( xPosition, yPosition, height );
232 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
234 mDecoratorUpdated = true;
236 else if( 2u == tapCount )
238 ChangeState( SELECTING );
242 void OnGrabHandleEvent( const Event& event )
244 unsigned int state = event.p1.mUint;
246 if( GRAB_HANDLE_PRESSED == state )
248 float xPosition = event.p2.mFloat;
249 float yPosition = event.p3.mFloat;
252 GetClosestCursorPosition( xPosition, yPosition, height );
254 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
255 mDecorator->HidePopup();
256 mDecoratorUpdated = true;
258 else if ( GRAB_HANDLE_RELEASED == state )
260 mDecorator->ShowPopup();
265 void ChangeState( State newState )
267 if( mState != newState )
271 if( INACTIVE == mState )
273 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
274 mDecorator->StopCursorBlink();
275 mDecorator->SetGrabHandleActive( false );
276 mDecorator->SetSelectionActive( false );
277 mDecorator->HidePopup();
278 mDecoratorUpdated = true;
280 else if ( SELECTING == mState )
282 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
283 mDecorator->StopCursorBlink();
284 mDecorator->SetGrabHandleActive( false );
285 mDecorator->SetSelectionActive( true );
286 mDecoratorUpdated = true;
288 else if( EDITING == mState )
290 mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
291 if( mCursorBlinkEnabled )
293 mDecorator->StartCursorBlink();
295 mDecorator->SetGrabHandleActive( true );
296 mDecorator->SetSelectionActive( false );
297 mDecoratorUpdated = true;
302 void GetClosestCursorPosition( float& x, float& y, float& height )
304 // TODO - Look at LineRuns first
306 Text::Length numberOfGlyphs = mVisualModel->GetNumberOfGlyphs();
307 if( 0 == numberOfGlyphs )
312 Vector<GlyphInfo> glyphs;
313 glyphs.Resize( numberOfGlyphs );
314 mVisualModel->GetGlyphs( glyphs.Begin(), 0, numberOfGlyphs );
315 const GlyphInfo* const glyphsBuffer = glyphs.Begin();
317 Vector<Vector2> positions;
318 positions.Resize( numberOfGlyphs );
319 mVisualModel->GetGlyphPositions( positions.Begin(), 0, numberOfGlyphs );
320 const Vector2* const positionsBuffer = positions.Begin();
322 unsigned int closestGlyph = 0;
323 float closestDistance = MAX_FLOAT;
325 for( unsigned int i = 0, numberOfGLyphs = glyphs.Count(); i < numberOfGLyphs; ++i )
327 const GlyphInfo& glyphInfo = *( glyphsBuffer + i );
328 const Vector2& position = *( positionsBuffer + i );
329 float glyphX = position.x + glyphInfo.width*0.5f;
330 float glyphY = position.y + glyphInfo.height*0.5f;
332 float distanceToGlyph = fabsf( glyphX - x ) + fabsf( glyphY - y );
334 if( distanceToGlyph < closestDistance )
336 closestDistance = distanceToGlyph;
341 // TODO - Consider RTL languages
342 x = positions[closestGlyph].x + glyphs[closestGlyph].width;
346 TextAbstraction::FontClient::Get().GetFontMetrics( glyphs[closestGlyph].fontId, metrics );
347 height = metrics.height; // TODO - Fix for multi-line
350 LogicalModelPtr mLogicalModel;
351 VisualModelPtr mVisualModel;
352 DecoratorPtr mDecorator;
354 std::string mPlaceholderText;
357 * This is used to delay handling events until after the model has been updated.
358 * The number of updates to the model is minimized to improve performance.
360 vector<Event> mEventQueue; ///< The queue of touch events etc.
364 bool mDecoratorUpdated : 1;
365 bool mCursorBlinkEnabled : 1;
368 struct Controller::FontDefaults
371 : mDefaultPointSize(0.0f),
376 FontId GetFontId( TextAbstraction::FontClient& fontClient )
380 Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
381 mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
387 std::string mDefaultFontFamily;
388 std::string mDefaultFontStyle;
389 float mDefaultPointSize;
393 struct Controller::Impl
395 Impl( ControlInterface& controlInterface )
396 : mControlInterface( controlInterface ),
399 mFontDefaults( NULL ),
406 mOperationsPending( NO_OPERATION ),
407 mRecalculateNaturalSize( true )
409 mLogicalModel = LogicalModel::New();
410 mVisualModel = VisualModel::New();
412 mFontClient = TextAbstraction::FontClient::Get();
414 mView.SetVisualModel( mVisualModel );
422 ControlInterface& mControlInterface; ///< Reference to the text controller.
423 LogicalModelPtr mLogicalModel; ///< Pointer to the logical model.
424 VisualModelPtr mVisualModel; ///< Pointer to the visual model.
425 FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
426 Controller::TextInput* mTextInput; ///< Avoid allocating everything for text input until EnableTextInput().
427 TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
428 View mView; ///< The view interface to the rendering back-end.
429 LayoutEngine mLayoutEngine; ///< The layout engine.
430 std::string mNewText; ///< Temporary stores the text set until the next relayout.
431 Size mControlSize; ///< The size of the control.
432 OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
433 bool mRecalculateNaturalSize:1; ///< Whether the natural size needs to be recalculated.
436 ControllerPtr Controller::New( ControlInterface& controlInterface )
438 return ControllerPtr( new Controller( controlInterface ) );
441 void Controller::SetText( const std::string& text )
443 // Keep until size negotiation
444 mImpl->mNewText = text;
446 // All operations need to be done. (convert to utf32, get break info, ..., layout, ...)
447 mImpl->mOperationsPending = ALL_OPERATIONS;
449 // The natural size needs to be re-calculated.
450 mImpl->mRecalculateNaturalSize = true;
453 mImpl->mLogicalModel->SetText( NULL, 0u );
454 mImpl->mLogicalModel->SetScripts( NULL, 0u );
455 mImpl->mLogicalModel->SetFonts( NULL, 0u );
456 mImpl->mLogicalModel->SetLineBreakInfo( NULL, 0u );
457 mImpl->mLogicalModel->SetWordBreakInfo( NULL, 0u );
458 mImpl->mLogicalModel->SetBidirectionalInfo( NULL, 0u );
459 mImpl->mLogicalModel->SetVisualToLogicalMap( NULL, 0u );
460 mImpl->mVisualModel->SetGlyphs( NULL, NULL, NULL, 0u );
461 mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
462 mImpl->mVisualModel->SetLines( NULL, 0u );
464 if( mImpl->mTextInput )
466 // Cancel previously queued events
467 mImpl->mTextInput->mEventQueue.clear();
469 // TODO - Hide selection decorations
473 void Controller::GetText( std::string& text ) const
475 if( !mImpl->mNewText.empty() )
477 text = mImpl->mNewText;
481 // TODO - Convert from UTF-32
485 void Controller::SetPlaceholderText( const std::string& text )
487 if( !mImpl->mTextInput )
489 mImpl->mTextInput->mPlaceholderText = text;
493 void Controller::GetPlaceholderText( std::string& text ) const
495 if( !mImpl->mTextInput )
497 text = mImpl->mTextInput->mPlaceholderText;
501 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
503 if( !mImpl->mFontDefaults )
505 mImpl->mFontDefaults = new Controller::FontDefaults();
508 mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
509 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
510 mImpl->mOperationsPending = ALL_OPERATIONS;
511 mImpl->mRecalculateNaturalSize = true;
514 const std::string& Controller::GetDefaultFontFamily() const
516 if( mImpl->mFontDefaults )
518 return mImpl->mFontDefaults->mDefaultFontFamily;
524 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
526 if( !mImpl->mFontDefaults )
528 mImpl->mFontDefaults = new Controller::FontDefaults();
531 mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
532 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
533 mImpl->mOperationsPending = ALL_OPERATIONS;
534 mImpl->mRecalculateNaturalSize = true;
537 const std::string& Controller::GetDefaultFontStyle() const
539 if( mImpl->mFontDefaults )
541 return mImpl->mFontDefaults->mDefaultFontStyle;
547 void Controller::SetDefaultPointSize( float pointSize )
549 if( !mImpl->mFontDefaults )
551 mImpl->mFontDefaults = new Controller::FontDefaults();
554 mImpl->mFontDefaults->mDefaultPointSize = pointSize;
555 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
556 mImpl->mOperationsPending = ALL_OPERATIONS;
557 mImpl->mRecalculateNaturalSize = true;
560 float Controller::GetDefaultPointSize() const
562 if( mImpl->mFontDefaults )
564 return mImpl->mFontDefaults->mDefaultPointSize;
570 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
572 if( mImpl->mFontDefaults )
575 fontRun.characterRun.characterIndex = 0;
576 fontRun.characterRun.numberOfCharacters = numberOfCharacters;
577 fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
578 fontRun.isDefault = true;
580 fonts.PushBack( fontRun );
584 void Controller::EnableTextInput( DecoratorPtr decorator )
586 if( !mImpl->mTextInput )
588 mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
592 void Controller::SetEnableCursorBlink( bool enable )
594 DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
596 if( mImpl->mTextInput )
598 mImpl->mTextInput->mCursorBlinkEnabled = enable;
601 mImpl->mTextInput->mDecorator )
603 mImpl->mTextInput->mDecorator->StopCursorBlink();
608 bool Controller::GetEnableCursorBlink() const
610 if( mImpl->mTextInput )
612 return mImpl->mTextInput->mCursorBlinkEnabled;
618 bool Controller::Relayout( const Vector2& size )
620 if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
622 bool glyphsRemoved( false );
623 if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
625 mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
626 glyphsRemoved = true;
629 // Not worth to relayout if width or height is equal to zero.
630 return glyphsRemoved;
633 if( size != mImpl->mControlSize )
635 // Operations that need to be done if the size changes.
636 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
643 mImpl->mControlSize = size;
646 // Make sure the model is up-to-date before layouting
647 ReplaceText( mImpl->mOperationsPending );
650 bool updated = DoRelayout( mImpl->mControlSize,
651 mImpl->mOperationsPending,
654 // Do not re-do any operation until something changes.
655 mImpl->mOperationsPending = NO_OPERATION;
657 if( mImpl->mTextInput )
659 // Move the cursor, grab handle etc.
660 updated = mImpl->mTextInput->ProcessInputEvents() || updated;
666 void Controller::ReplaceText( OperationsMask operationsRequired )
668 // Calculate the operations to be done.
669 const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
671 Vector<Character> utf32Characters;
672 Length characterCount = 0u;
673 if( CONVERT_TO_UTF32 & operations )
675 std::string& text = mImpl->mNewText;
677 // Convert text into UTF-32
678 utf32Characters.Resize( text.size() );
680 // This is a bit horrible but std::string returns a (signed) char*
681 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
683 // Transform a text array encoded in utf8 into an array encoded in utf32.
684 // It returns the actual number of characters.
685 characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
686 utf32Characters.Resize( characterCount );
688 // Sets the text into the model.
689 mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
691 // Discard temporary text
695 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
697 Vector<LineBreakInfo> lineBreakInfo;
698 if( GET_LINE_BREAKS & operations )
700 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
701 // calculate the bidirectional info for each 'paragraph'.
702 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
703 // is not shaped together).
704 lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
706 SetLineBreakInfo( utf32Characters,
709 mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
712 Vector<WordBreakInfo> wordBreakInfo;
713 if( GET_WORD_BREAKS & operations )
715 // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
716 wordBreakInfo.Resize( characterCount, TextAbstraction::WORD_NO_BREAK );
718 SetWordBreakInfo( utf32Characters,
721 mImpl->mLogicalModel->SetWordBreakInfo( wordBreakInfo.Begin(), characterCount );
724 const bool getScripts = GET_SCRIPTS & operations;
725 const bool validateFonts = VALIDATE_FONTS & operations;
727 Vector<ScriptRun> scripts;
728 Vector<FontRun> validFonts;
730 if( getScripts || validateFonts )
732 // Validates the fonts assigned by the application or assigns default ones.
733 // It makes sure all the characters are going to be rendered by the correct font.
734 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
738 // Retrieves the scripts used in the text.
739 multilanguageSupport.SetScripts( utf32Characters,
743 // Sets the scripts into the model.
744 mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
749 // Copy the requested font defaults received via the property system.
750 // These may not be valid i.e. may not contain glyphs for the necessary scripts.
751 GetDefaultFonts( validFonts, numberOfCharacters );
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,
759 // Sets the fonts into the model.
760 mImpl->mLogicalModel->SetFonts( validFonts.Begin(), validFonts.Count() );
764 if( BIDI_INFO & operations )
766 // Some vectors with data needed to get the paragraph's bidirectional info may be void
767 // after the first time the text has been laid out.
768 // Fill the vectors again.
770 if( 0u == utf32Characters.Count() )
772 utf32Characters.Resize( numberOfCharacters );
774 mImpl->mLogicalModel->GetText( utf32Characters.Begin(),
776 numberOfCharacters );
779 if( 0u == lineBreakInfo.Count() )
781 lineBreakInfo.Resize( numberOfCharacters );
783 mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
785 numberOfCharacters );
788 if( 0u == scripts.Count() )
790 scripts.Resize( mImpl->mLogicalModel->GetNumberOfScriptRuns( 0u,
791 numberOfCharacters ) );
792 mImpl->mLogicalModel->GetScriptRuns( scripts.Begin(),
794 numberOfCharacters );
797 // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
798 // bidirectional info.
800 Length numberOfParagraphs = 0u;
802 const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
803 for( Length index = 0u; index < characterCount; ++index )
805 if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
807 ++numberOfParagraphs;
811 Vector<BidirectionalParagraphInfoRun> bidirectionalInfo;
812 bidirectionalInfo.Reserve( numberOfParagraphs );
814 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
815 SetBidirectionalInfo( utf32Characters,
820 mImpl->mLogicalModel->SetBidirectionalInfo( bidirectionalInfo.Begin(),
821 bidirectionalInfo.Count() );
824 Vector<GlyphInfo> glyphs;
825 Vector<CharacterIndex> glyphsToCharactersMap;
826 Vector<Length> charactersPerGlyph;
827 if( SHAPE_TEXT & operations )
829 if( 0u == validFonts.Count() )
831 validFonts.Resize( mImpl->mLogicalModel->GetNumberOfFontRuns( 0u,
832 numberOfCharacters ) );
833 mImpl->mLogicalModel->GetFontRuns( validFonts.Begin(),
835 numberOfCharacters );
839 ShapeText( utf32Characters,
844 glyphsToCharactersMap,
845 charactersPerGlyph );
848 if( GET_GLYPH_METRICS & operations )
850 mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
853 Length numberOfGlyphs = glyphs.Count();
854 if( 0u != numberOfGlyphs )
856 // Sets the glyphs into the model.
857 mImpl->mVisualModel->SetGlyphs( glyphs.Begin(),
858 glyphsToCharactersMap.Begin(),
859 charactersPerGlyph.Begin(),
864 bool Controller::DoRelayout( const Vector2& size,
865 OperationsMask operationsRequired,
868 bool viewUpdated( false );
870 // Calculate the operations to be done.
871 const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
873 if( LAYOUT & operations )
875 // Some vectors with data needed to layout and reorder may be void
876 // after the first time the text has been laid out.
877 // Fill the vectors again.
879 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
880 Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
882 Vector<LineBreakInfo> lineBreakInfo;
883 lineBreakInfo.Resize( numberOfCharacters );
884 mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
886 numberOfCharacters );
888 Vector<WordBreakInfo> wordBreakInfo;
889 wordBreakInfo.Resize( numberOfCharacters );
890 mImpl->mLogicalModel->GetWordBreakInfo( wordBreakInfo.Begin(),
892 numberOfCharacters );
894 Vector<GlyphInfo> glyphs;
895 glyphs.Resize( numberOfGlyphs );
896 mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
900 Vector<CharacterIndex> glyphsToCharactersMap;
901 glyphsToCharactersMap.Resize( numberOfGlyphs );
902 mImpl->mVisualModel->GetGlyphToCharacterMap( glyphsToCharactersMap.Begin(),
906 Vector<Length> charactersPerGlyph;
907 charactersPerGlyph.Resize( numberOfGlyphs );
908 mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
912 // Set the layout parameters.
913 LayoutParameters layoutParameters( size,
914 lineBreakInfo.Begin(),
915 wordBreakInfo.Begin(),
918 glyphsToCharactersMap.Begin(),
919 charactersPerGlyph.Begin() );
921 // Reserve space to set the positions of the glyphs.
922 Vector<Vector2> glyphPositions;
923 glyphPositions.Resize( numberOfGlyphs );
925 // The laid-out lines.
926 // It's not possible to know in how many lines the text is going to be laid-out,
927 // but it can be resized at least with the number of 'paragraphs' to avoid
928 // some re-allocations.
929 Vector<LineRun> lines;
930 lines.Reserve( mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters ) );
932 // Update the visual model.
933 viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
941 if( REORDER & operations )
943 const Length numberOfBidiParagraphs = mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters );
945 Vector<BidirectionalParagraphInfoRun> bidirectionalInfo;
946 bidirectionalInfo.Resize( numberOfBidiParagraphs );
947 mImpl->mLogicalModel->GetBidirectionalInfo( bidirectionalInfo.Begin(),
949 numberOfCharacters );
951 // Check first if there are paragraphs with bidirectional info.
952 if( 0u != bidirectionalInfo.Count() )
955 const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
957 // Reorder the lines.
958 Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
959 lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
960 ReorderLines( bidirectionalInfo,
962 lineBidirectionalInfoRuns );
964 // Set the bidirectional info into the model.
965 const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
966 mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
967 numberOfBidirectionalInfoRuns );
969 // Set the bidirectional info per line into the layout parameters.
970 layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
971 layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
973 // Get the character to glyph conversion table and set into the layout.
974 Vector<GlyphIndex> characterToGlyphMap;
975 characterToGlyphMap.Resize( numberOfCharacters );
977 layoutParameters.charactersToGlyphsBuffer = characterToGlyphMap.Begin();
978 mImpl->mVisualModel->GetCharacterToGlyphMap( layoutParameters.charactersToGlyphsBuffer,
980 numberOfCharacters );
982 // Get the glyphs per character table and set into the layout.
983 Vector<Length> glyphsPerCharacter;
984 glyphsPerCharacter.Resize( numberOfCharacters );
986 layoutParameters.glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
987 mImpl->mVisualModel->GetGlyphsPerCharacterMap( layoutParameters.glyphsPerCharacterBuffer,
989 numberOfCharacters );
991 // Re-layout the text. Reorder those lines with right to left characters.
992 mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
995 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
996 for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
997 endIt = lineBidirectionalInfoRuns.End();
1001 BidirectionalLineInfoRun& bidiLineInfo = *it;
1003 free( bidiLineInfo.visualToLogicalMap );
1008 // Sets the positions into the model.
1009 if( UPDATE_POSITIONS & operations )
1011 mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(),
1015 // Sets the lines into the model.
1016 if( UPDATE_LINES & operations )
1018 mImpl->mVisualModel->SetLines( lines.Begin(),
1022 // Sets the actual size.
1023 if( UPDATE_ACTUAL_SIZE & operations )
1025 mImpl->mVisualModel->SetActualSize( layoutSize );
1031 layoutSize = mImpl->mVisualModel->GetActualSize();
1037 Vector3 Controller::GetNaturalSize()
1039 Vector3 naturalSize;
1041 if( mImpl->mRecalculateNaturalSize )
1043 // Operations that can be done only once until the text changes.
1044 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
1050 GET_GLYPH_METRICS );
1051 // Make sure the model is up-to-date before layouting
1052 ReplaceText( onlyOnceOperations );
1054 // Operations that need to be done if the size changes.
1055 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
1058 DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1059 static_cast<OperationsMask>( onlyOnceOperations |
1061 naturalSize.GetVectorXY() );
1063 // Do not do again the only once operations.
1064 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1066 // Do the size related operations again.
1067 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1069 // Stores the natural size to avoid recalculate it again
1070 // unless the text/style changes.
1071 mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1073 mImpl->mRecalculateNaturalSize = false;
1077 naturalSize = mImpl->mVisualModel->GetNaturalSize();
1083 float Controller::GetHeightForWidth( float width )
1086 if( width != mImpl->mControlSize.width )
1088 // Operations that can be done only once until the text changes.
1089 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
1095 GET_GLYPH_METRICS );
1097 // Make sure the model is up-to-date before layouting
1098 ReplaceText( onlyOnceOperations );
1100 // Operations that need to be done if the size changes.
1101 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
1104 DoRelayout( Size( width, MAX_FLOAT ),
1105 static_cast<OperationsMask>( onlyOnceOperations |
1109 // Do not do again the only once operations.
1110 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1112 // Do the size related operations again.
1113 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1117 layoutSize = mImpl->mVisualModel->GetActualSize();
1120 return layoutSize.height;
1123 View& Controller::GetView()
1125 return mImpl->mView;
1128 LayoutEngine& Controller::GetLayoutEngine()
1130 return mImpl->mLayoutEngine;
1133 void Controller::RequestRelayout()
1135 mImpl->mControlInterface.RequestTextRelayout();
1138 void Controller::KeyboardFocusGainEvent()
1140 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1142 if( mImpl->mTextInput )
1144 TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1145 mImpl->mTextInput->mEventQueue.push_back( event );
1151 void Controller::KeyboardFocusLostEvent()
1153 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1155 if( mImpl->mTextInput )
1157 TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1158 mImpl->mTextInput->mEventQueue.push_back( event );
1164 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1166 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1168 if( mImpl->mTextInput )
1170 TextInput::Event event( TextInput::KEY_EVENT );
1171 event.p1.mInt = keyEvent.keyCode;
1172 event.p2.mString = NULL;
1174 const std::string& keyString = keyEvent.keyPressed;
1175 if ( !keyString.empty() )
1177 event.p2.mString = new char[keyString.size() + 1];
1178 std::copy(keyString.begin(), keyString.end(), event.p2.mString);
1179 event.p2.mString[keyString.size()] = '\0';
1182 mImpl->mTextInput->mEventQueue.push_back( event );
1190 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1192 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1194 if( mImpl->mTextInput )
1196 TextInput::Event event( TextInput::TAP_EVENT );
1197 event.p1.mUint = tapCount;
1198 event.p2.mFloat = x;
1199 event.p3.mFloat = y;
1200 mImpl->mTextInput->mEventQueue.push_back( event );
1206 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1208 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1210 if( mImpl->mTextInput )
1212 TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1213 event.p1.mUint = state;
1214 event.p2.mFloat = x;
1215 event.p3.mFloat = y;
1216 mImpl->mTextInput->mEventQueue.push_back( event );
1222 Controller::~Controller()
1227 Controller::Controller( ControlInterface& controlInterface )
1230 mImpl = new Controller::Impl( controlInterface );
1235 } // namespace Toolkit