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