Merge branch 'tizen' into devel/new_mesh
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-view / split-by-char-policies.cpp
1 /*
2  * Copyright (c) 2014 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 // FILE HEADER
19 #include <dali-toolkit/internal/controls/text-view/split-by-char-policies.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/controls/text-view/relayout-utilities.h>
26 #include <dali-toolkit/internal/controls/text-view/text-view-processor.h>
27
28 namespace Dali
29 {
30
31 namespace Toolkit
32 {
33
34 namespace Internal
35 {
36
37 namespace SplitByChar
38 {
39
40 namespace
41 {
42
43 Vector3 NoShrinkWhenExceedPosition( const TextViewRelayout::RelayoutParameters& relayoutParameters,
44                                     const TextView::LayoutParameters& layoutParameters,
45                                     TextView::RelayoutData& relayoutData )
46 {
47   const float wordOffset = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.x );
48   const float previousPositionY = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.y );
49
50   if( ( relayoutParameters.mIsNewLine ||
51         relayoutParameters.mIsFirstCharacter ||
52         ( wordOffset + relayoutParameters.mCharacterSize.width > relayoutData.mTextViewSize.width ) ) )
53   {
54     if( !relayoutParameters.mIsNewLine &&
55         ( relayoutParameters.mIsWhiteSpace || relayoutParameters.mIsNewParagraphCharacter ) )
56     {
57       // Current character is a white space. Don't want to move a white space to the next line.
58       // These white spaces are placed just in the edge.
59       return Vector3( relayoutData.mTextViewSize.width - relayoutParameters.mWordSize.width, relayoutParameters.mPositionOffset.y, 0.f );
60     }
61     else
62     {
63       // Calculate the line length and the max character height for the current line.
64       TextViewRelayout::LineLayoutInfo subLineInfo;
65       subLineInfo.mLineLength = 0.f;
66       subLineInfo.mMaxCharHeight = 0.f;
67       subLineInfo.mMaxAscender = 0.f;
68       const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + relayoutParameters.mIndices.mParagraphIndex ) );
69
70       TextViewRelayout::CalculateLineLayout( relayoutData.mTextViewSize.width,
71                                              relayoutParameters.mIndices,
72                                              paragraphLayoutInfo,
73                                              TextViewRelayout::WrapByCharacter,
74                                              1.f, // Shrink factor
75                                              subLineInfo );
76
77       Toolkit::TextView::LineLayoutInfo lineInfo;
78       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
79       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
80       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of paragraph.
81       relayoutData.mLines.push_back( lineInfo );
82
83       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset, 0.f );
84     }
85   }
86   else
87   {
88     return Vector3( wordOffset, previousPositionY, 0.f );
89   }
90 }
91
92 void CalculateSizeAndPosition( const TextView::LayoutParameters& layoutParameters,
93                                TextView::RelayoutData& relayoutData )
94 {
95   TextViewRelayout::RelayoutParameters relayoutParameters;
96
97   // clear
98   relayoutData.mCharacterLayoutInfoTable.clear();
99   relayoutData.mLines.clear();
100   relayoutData.mTextSizeForRelayoutOption = Size();
101
102   // Calculate the text size for split by char.
103   Vector4 minMaxXY( std::numeric_limits<float>::max(),
104                     std::numeric_limits<float>::max(),
105                     std::numeric_limits<float>::min(),
106                     std::numeric_limits<float>::min() );
107
108   relayoutData.mShrinkFactor = 1.f; // Shrink factor used when the exceed policy contains ShrinkToFit
109
110   relayoutParameters.mPositionOffset = Vector3::ZERO;
111   relayoutParameters.mIsFirstCharacter = true;
112   relayoutParameters.mIndices.mParagraphIndex = 0u;
113   relayoutParameters.mCharacterGlobalIndex = 0u;
114
115   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
116          endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
117        paragraphLayoutIt != endParagraphLayoutIt;
118        ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
119   {
120     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
121
122     relayoutParameters.mIsNewLine = true;
123     relayoutParameters.mParagraphSize = paragraphLayoutInfo.mSize;
124     relayoutParameters.mIndices.mWordIndex = 0u;
125
126     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(),
127            endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
128          wordLayoutIt != endWordLayoutIt;
129          ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
130     {
131       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
132       relayoutParameters.mIsWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
133       relayoutParameters.mIsNewParagraphCharacter = TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType;
134
135       relayoutParameters.mIsFirstCharacterOfWord = true;
136       relayoutParameters.mWordSize = wordLayoutInfo.mSize;
137       relayoutParameters.mIndices.mCharacterIndex = 0u;
138
139       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
140              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
141            characterLayoutIt != endCharacterLayoutIt;
142            ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex )
143       {
144         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
145
146         relayoutParameters.mCharacterSize = characterLayoutInfo.mSize;
147
148         switch( layoutParameters.mExceedPolicy )
149         {
150           case TextView::OriginalShrink:
151           case TextView::SplitOriginal:
152           case TextView::SplitFade:
153           case TextView::SplitEllipsizeEnd:
154           case TextView::SplitShrink:
155           case TextView::ShrinkOriginal:
156           case TextView::ShrinkFade:
157           case TextView::Shrink:
158           case TextView::EllipsizeEndOriginal:
159           case TextView::EllipsizeEnd: // Fall Through
160           {
161             DALI_LOG_WARNING( "SplitByChar::CalculateSizeAndPosition() policy not implemented.\n" );
162             break;
163           }
164           case TextView::OriginalFade:
165           case TextView::FadeOriginal:
166           case TextView::Original:
167           case TextView::Fade: // Fall Through
168           {
169             characterLayoutInfo.mPosition = NoShrinkWhenExceedPosition( relayoutParameters,
170                                                                         layoutParameters,
171                                                                         relayoutData );
172
173             relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width, 0.f, 0.f );
174             break;
175           }
176           default:
177           {
178             DALI_LOG_WARNING( "SplitByChar::CalculateSizeAndPosition() policy combination not possible.\n" );
179           }
180         }
181
182         // Get last line info and calculate the bearing (used to align glyphs with the baseline).
183         TextViewRelayout::CalculateBearing( characterLayoutInfo, relayoutData );
184
185         // updates min and max position to calculate the text size for split by char.
186         TextViewRelayout::UpdateLayoutInfoTable( minMaxXY,
187                                                  wordLayoutInfo,
188                                                  characterLayoutInfo,
189                                                  relayoutParameters,
190                                                  relayoutData );
191
192         ++relayoutParameters.mCharacterGlobalIndex;
193         relayoutParameters.mIsFirstCharacter = false;
194         relayoutParameters.mIsNewLine = false;
195       } // end characters
196     } // end words
197   } // end paragraphs
198
199   if( relayoutData.mCharacterLayoutInfoTable.empty() )
200   {
201     relayoutData.mTextSizeForRelayoutOption = Size();
202   }
203   else
204   {
205     relayoutData.mTextSizeForRelayoutOption.width = minMaxXY.z - minMaxXY.x;
206     relayoutData.mTextSizeForRelayoutOption.height = minMaxXY.w - minMaxXY.y;
207   }
208
209   // Check if the last character is a new paragraph character. In that case the height should be added.
210   if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
211   {
212     const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
213
214     if( paragraphLayoutInfo.mWordsLayoutInfo.empty() ) // if it's empty, it means the last character is a new paragraph character.
215     {
216       relayoutData.mTextSizeForRelayoutOption.height += paragraphLayoutInfo.mSize.height;
217     }
218   }
219 }
220
221 } // namespace
222
223 void Relayout( Actor textView,
224                TextView::RelayoutOperationMask relayoutOperationMask,
225                const TextView::LayoutParameters& layoutParameters,
226                const TextView::VisualParameters& visualParameters,
227                TextView::RelayoutData& relayoutData )
228 {
229   if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION )
230   {
231     CalculateSizeAndPosition( layoutParameters,
232                               relayoutData );
233
234     TextViewRelayout::ReorderRightToLeftLayout( relayoutData );
235
236     TextViewRelayout::SetUnderlineInfo( relayoutData );
237   }
238
239   if( relayoutOperationMask & TextView::RELAYOUT_ALIGNMENT )
240   {
241     TextViewRelayout::UpdateAlignment( layoutParameters,
242                                        relayoutData );
243   }
244
245   if( relayoutOperationMask & TextView::RELAYOUT_VISIBILITY )
246   {
247     TextViewRelayout::UpdateVisibility( layoutParameters,
248                                         visualParameters,
249                                         relayoutData );
250   }
251
252   const bool initializeTextActors = relayoutOperationMask & TextView::RELAYOUT_INITIALIZE_TEXT_ACTORS;
253   const bool updateTextActors = relayoutOperationMask & TextView::RELAYOUT_TEXT_ACTOR_UPDATE;
254   if( initializeTextActors || updateTextActors )
255   {
256     TextViewRelayout::UpdateTextActorInfo( visualParameters,
257                                            relayoutData,
258                                            initializeTextActors );
259   }
260
261   if( relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW )
262   {
263     TextViewRelayout::InsertToTextView( textView,
264                                         relayoutData );
265   }
266 }
267
268 } // namespace SplitByChar
269
270 } // namespace Internal
271
272 } // namespace Toolkit
273
274 } // namespace Dali