Fixed crash in case that overshoot scroll is not enabled
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-view / split-by-new-line-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-new-line-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 SplitByNewLineChar
36 {
37
38 namespace
39 {
40
41 Vector3 SplitPosition( 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.mIsNewParagraphCharacter ) )
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       const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + relayoutParameters.mIndices.mParagraphIndex ) );
62
63       TextViewRelayout::LineLayoutInfo subLineInfo;
64       subLineInfo.mLineLength = 0.f;
65       subLineInfo.mMaxCharHeight = 0.f;
66       subLineInfo.mMaxAscender = 0.f;
67       TextViewRelayout::CalculateLineLayout( relayoutData.mTextViewSize.width,
68                                              relayoutParameters.mIndices,
69                                              paragraphLayoutInfo,
70                                              TextViewRelayout::WrapByParagraphCharacterAndSplit,
71                                              1.f, // Shrink factor
72                                              subLineInfo );
73
74       Toolkit::TextView::LineLayoutInfo lineInfo;
75       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
76       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
77       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of paragraph.
78       relayoutData.mLines.push_back( lineInfo );
79
80       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset, 0.f );
81     }
82   }
83   else
84   {
85     return Vector3( wordOffset, previousPositionY, 0.f );
86   }
87 }
88
89 void CalculateSizeAndPosition( const TextView::LayoutParameters& layoutParameters,
90                                TextView::RelayoutData& relayoutData )
91 {
92   // clear
93   relayoutData.mCharacterLayoutInfoTable.clear();
94   relayoutData.mLines.clear();
95   relayoutData.mTextSizeForRelayoutOption = Size();
96   relayoutData.mShrinkFactor = 1.f;
97
98   // Calculates the text size for split by char.
99   Vector4 minMaxXY( std::numeric_limits<float>::max(),
100                     std::numeric_limits<float>::max(),
101                     std::numeric_limits<float>::min(),
102                     std::numeric_limits<float>::min() );
103
104   TextViewRelayout::RelayoutParameters relayoutParameters;
105
106   if( TextView::ShrinkOriginal == layoutParameters.mExceedPolicy )
107   {
108     if( relayoutData.mTextLayoutInfo.mWholeTextSize.width > relayoutData.mTextViewSize.width )
109     {
110       relayoutData.mShrinkFactor = relayoutData.mTextViewSize.width / relayoutData.mTextLayoutInfo.mWholeTextSize.width;
111     }
112   }
113   else if( TextView::Shrink == layoutParameters.mExceedPolicy )
114   {
115     if( ( relayoutData.mTextLayoutInfo.mWholeTextSize.width > relayoutData.mTextViewSize.width ) ||
116         ( relayoutData.mTextLayoutInfo.mWholeTextSize.height > relayoutData.mTextViewSize.height ) )
117     {
118       relayoutData.mShrinkFactor = std::min( relayoutData.mTextViewSize.width / relayoutData.mTextLayoutInfo.mWholeTextSize.width,
119                                              relayoutData.mTextViewSize.height / relayoutData.mTextLayoutInfo.mWholeTextSize.height );
120     }
121   }
122
123   relayoutParameters.mIsFirstCharacter = true;
124   relayoutParameters.mIndices.mParagraphIndex = 0u;
125   relayoutParameters.mPositionOffset = Vector3::ZERO;
126   relayoutParameters.mCharacterGlobalIndex = 0u;
127
128   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
129        endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
130        paragraphLayoutIt != endParagraphLayoutIt;
131        ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
132   {
133     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
134
135     relayoutParameters.mParagraphSize = paragraphLayoutInfo.mSize * relayoutData.mShrinkFactor;
136
137     relayoutParameters.mIsNewLine = true;
138     relayoutParameters.mIndices.mWordIndex = 0u;
139
140     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(),
141            endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
142          wordLayoutIt != endWordLayoutIt;
143          ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
144     {
145       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
146       relayoutParameters.mIsWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
147       relayoutParameters.mIsNewParagraphCharacter = TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType;
148
149       relayoutParameters.mIsFirstCharacterOfWord = true;
150       relayoutParameters.mWordSize = wordLayoutInfo.mSize;
151       relayoutParameters.mIndices.mCharacterIndex = 0u;
152
153       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
154              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
155            characterLayoutIt != endCharacterLayoutIt;
156            ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex )
157       {
158         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
159         relayoutParameters.mCharacterSize = characterLayoutInfo.mSize;
160
161         relayoutParameters.mCharacterSize = characterLayoutInfo.mSize;
162
163         switch( layoutParameters.mExceedPolicy )
164         {
165           case TextView::OriginalShrink:
166           case TextView::SplitShrink:
167           case TextView::ShrinkFade: // Fall Through
168           {
169             DALI_LOG_WARNING( "SplitByNewLineChar::CalculateSizeAndPosition() policy not implemented.\n" );
170             break;
171           }
172           case TextView::Original: // Fall Through
173           case TextView::ShrinkOriginal: // Fall Through
174           case TextView::Shrink: // Fall Through
175           case TextView::OriginalFade: // Fall Through
176           case TextView::FadeOriginal: // Fall Through
177           case TextView::Fade: // Fall Through
178           case TextView::EllipsizeEndOriginal: // Fall Through
179           case TextView::EllipsizeEnd: // Fall Through
180           {
181             if( relayoutParameters.mIsNewLine )
182             {
183               relayoutParameters.mPositionOffset.x = 0.f;
184               relayoutParameters.mPositionOffset.y += paragraphLayoutInfo.mSize.height * relayoutData.mShrinkFactor;
185             }
186
187             characterLayoutInfo.mPosition = relayoutParameters.mPositionOffset;
188
189             relayoutParameters.mPositionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
190
191             if( relayoutParameters.mIsNewLine ||
192                 relayoutParameters.mIsFirstCharacter )
193             {
194               Toolkit::TextView::LineLayoutInfo lineInfo;
195               lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;       // Index to the first character of the next line.
196               lineInfo.mSize = relayoutParameters.mParagraphSize;                              // Size of this piece of paragraph.
197               lineInfo.mAscender = paragraphLayoutInfo.mAscender * relayoutData.mShrinkFactor; // Ascender of this piece of paragraph.
198               relayoutData.mLines.push_back( lineInfo );
199             }
200             break;
201           }
202           case TextView::SplitOriginal:
203           case TextView::SplitFade:
204           case TextView::SplitEllipsizeEnd: // Fall Through
205           {
206             characterLayoutInfo.mPosition = SplitPosition( relayoutParameters,
207                                                            layoutParameters,
208                                                            relayoutData );
209
210             relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width, 0.f, 0.f );
211             break;
212           }
213           default:
214           {
215             DALI_LOG_WARNING( "SplitByNewLineChar::CalculateSizeAndPosition() Layout configuration not possible.\n" );
216             break;
217           }
218         }
219
220         // Get last line info and calculate the bearing (used to align glyphs with the baseline).
221         TextViewRelayout::CalculateBearing( characterLayoutInfo, relayoutData );
222
223         // updates min and max position to calculate the text size for split by new line char.
224         TextViewRelayout::UpdateLayoutInfoTable( minMaxXY,
225                                                  wordLayoutInfo,
226                                                  characterLayoutInfo,
227                                                  relayoutParameters,
228                                                  relayoutData );
229
230         ++relayoutParameters.mCharacterGlobalIndex;
231         relayoutParameters.mIsFirstCharacter = false;
232         relayoutParameters.mIsNewLine = false;
233       } // end characters
234     } // end words
235   } // end paragraphs
236
237   if( relayoutData.mCharacterLayoutInfoTable.empty() )
238   {
239     relayoutData.mTextSizeForRelayoutOption = Size();
240   }
241   else
242   {
243     relayoutData.mTextSizeForRelayoutOption.width = minMaxXY.z - minMaxXY.x;
244     relayoutData.mTextSizeForRelayoutOption.height = minMaxXY.w - minMaxXY.y;
245   }
246
247   // Check if the last character is a new paragraph character. In that case the height should be added.
248   if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
249   {
250     const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
251
252     if( paragraphLayoutInfo.mWordsLayoutInfo.empty() ) // if it's empty, it means the last character is a new paragraph character.
253     {
254       relayoutData.mTextSizeForRelayoutOption.height += paragraphLayoutInfo.mSize.height * relayoutData.mShrinkFactor;
255     }
256   }
257 }
258
259 } // namespace
260
261 void Relayout( Actor textView,
262                TextView::RelayoutOperationMask relayoutOperationMask,
263                const TextView::LayoutParameters& layoutParameters,
264                const TextView::VisualParameters& visualParameters,
265                TextView::RelayoutData& relayoutData )
266 {
267   if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION )
268   {
269     CalculateSizeAndPosition( layoutParameters,
270                               relayoutData );
271
272     TextViewRelayout::ReorderRightToLeftLayout( relayoutData );
273
274     TextViewRelayout::SetUnderlineInfo( relayoutData );
275   }
276
277   if( relayoutOperationMask & TextView::RELAYOUT_ALIGNMENT )
278   {
279     TextViewRelayout::UpdateAlignment( layoutParameters,
280                                        relayoutData );
281   }
282
283   if( relayoutOperationMask & TextView::RELAYOUT_VISIBILITY )
284   {
285     TextViewRelayout::UpdateVisibility( layoutParameters,
286                                         visualParameters,
287                                         relayoutData );
288   }
289
290   const bool initializeTextActors = relayoutOperationMask & TextView::RELAYOUT_INITIALIZE_TEXT_ACTORS;
291   const bool updateTextActors = relayoutOperationMask & TextView::RELAYOUT_TEXT_ACTOR_UPDATE;
292   if( initializeTextActors || updateTextActors )
293   {
294     TextViewRelayout::UpdateTextActorInfo( visualParameters,
295                                            relayoutData,
296                                            initializeTextActors );
297   }
298
299   if( relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW )
300   {
301     TextViewRelayout::InsertToTextView( textView,
302                                         relayoutData );
303   }
304 }
305
306 } // namespace SplitByNewLineChar
307
308 } // namespace Internal
309
310 } // namespace Toolkit
311
312 } // namespace Dali