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