[dali_2.1.31] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / controller / text-controller-input-font-handler.cpp
1 /*
2  * Copyright (c) 2022 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 // CLASS HEADER
19 #include <dali-toolkit/internal/text/controller/text-controller-input-font-handler.h>
20
21 // EXTERNAL INCLUDES
22 #include <memory.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/text/controller/text-controller-impl.h>
26
27 namespace Dali
28 {
29 namespace Toolkit
30 {
31 namespace Text
32 {
33 namespace
34 {
35 /**
36  * @brief Adds a new font description run for the selected text.
37  *
38  * The new font parameters are added after the call to this method.
39  *
40  * @param[in] eventData The event data pointer.
41  * @param[in] logicalModel The logical model where to add the new font description run.
42  * @param[out] startOfSelectedText Index to the first selected character.
43  * @param[out] lengthOfSelectedText Number of selected characters.
44  */
45 FontDescriptionRun& UpdateSelectionFontStyleRun(EventData*      eventData,
46                                                 LogicalModelPtr logicalModel,
47                                                 CharacterIndex& startOfSelectedText,
48                                                 Length&         lengthOfSelectedText)
49 {
50   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
51
52   // Get start and end position of selection
53   startOfSelectedText  = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
54   lengthOfSelectedText = (handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition) - startOfSelectedText;
55
56   // Add the font run.
57   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
58   logicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
59
60   FontDescriptionRun& fontDescriptionRun = *(logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
61
62   fontDescriptionRun.characterRun.characterIndex     = startOfSelectedText;
63   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
64
65   // Recalculate the selection highlight as the metrics may have changed.
66   eventData->mUpdateLeftSelectionPosition  = true;
67   eventData->mUpdateRightSelectionPosition = true;
68   eventData->mUpdateHighlightBox           = true;
69
70   return fontDescriptionRun;
71 }
72
73 } // unnamed namespace
74
75 void Controller::InputFontHandler::SetInputFontFamily(Controller& controller, const std::string& fontFamily)
76 {
77   if(NULL != controller.mImpl->mEventData)
78   {
79     controller.mImpl->mEventData->mInputStyle.familyName      = fontFamily;
80     controller.mImpl->mEventData->mInputStyle.isFamilyDefined = true;
81
82     if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
83     {
84       CharacterIndex startOfSelectedText  = 0u;
85       Length         lengthOfSelectedText = 0u;
86
87       if(EventData::SELECTING == controller.mImpl->mEventData->mState)
88       {
89         // Update a font description run for the selecting state.
90         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
91                                                                              controller.mImpl->mModel->mLogicalModel,
92                                                                              startOfSelectedText,
93                                                                              lengthOfSelectedText);
94
95         fontDescriptionRun.familyLength = fontFamily.size();
96         fontDescriptionRun.familyName   = new char[fontDescriptionRun.familyLength];
97         memcpy(fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength);
98         fontDescriptionRun.familyDefined = true;
99
100         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
101
102         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
103         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
104         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
105       }
106       else
107       {
108         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
109         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
110         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = controller.mImpl->mModel->mLogicalModel->mText.Count();
111       }
112
113       // Request to relayout.
114       controller.mImpl->mOperationsPending      = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
115                                                                          VALIDATE_FONTS |
116                                                                          SHAPE_TEXT |
117                                                                          GET_GLYPH_METRICS |
118                                                                          LAYOUT |
119                                                                          UPDATE_LAYOUT_SIZE |
120                                                                          REORDER |
121                                                                          ALIGN);
122       controller.mImpl->mRecalculateNaturalSize = true;
123       controller.mImpl->RequestRelayout();
124
125       // As the font changes, recalculate the handle positions is needed.
126       controller.mImpl->mEventData->mUpdateLeftSelectionPosition  = true;
127       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
128       controller.mImpl->mEventData->mUpdateHighlightBox           = true;
129       controller.mImpl->mEventData->mScrollAfterUpdatePosition    = true;
130     }
131   }
132 }
133
134 const std::string& Controller::InputFontHandler::GetInputFontFamily(const Controller& controller)
135 {
136   if(NULL != controller.mImpl->mEventData)
137   {
138     return controller.mImpl->mEventData->mInputStyle.familyName;
139   }
140
141   // Return the default font's family if there is no EventData.
142   return controller.GetDefaultFontFamily();
143 }
144
145 void Controller::InputFontHandler::SetInputFontWeight(const Controller& controller, FontWeight weight)
146 {
147   if(NULL != controller.mImpl->mEventData)
148   {
149     controller.mImpl->mEventData->mInputStyle.weight          = weight;
150     controller.mImpl->mEventData->mInputStyle.isWeightDefined = true;
151
152     if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
153     {
154       CharacterIndex startOfSelectedText  = 0u;
155       Length         lengthOfSelectedText = 0u;
156
157       if(EventData::SELECTING == controller.mImpl->mEventData->mState)
158       {
159         // Update a font description run for the selecting state.
160         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
161                                                                              controller.mImpl->mModel->mLogicalModel,
162                                                                              startOfSelectedText,
163                                                                              lengthOfSelectedText);
164
165         fontDescriptionRun.weight        = weight;
166         fontDescriptionRun.weightDefined = true;
167
168         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
169         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
170         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
171       }
172       else
173       {
174         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
175         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
176         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = controller.mImpl->mModel->mLogicalModel->mText.Count();
177       }
178
179       // Request to relayout.
180       controller.mImpl->mOperationsPending      = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
181                                                                          VALIDATE_FONTS |
182                                                                          SHAPE_TEXT |
183                                                                          GET_GLYPH_METRICS |
184                                                                          LAYOUT |
185                                                                          UPDATE_LAYOUT_SIZE |
186                                                                          REORDER |
187                                                                          ALIGN);
188       controller.mImpl->mRecalculateNaturalSize = true;
189       controller.mImpl->RequestRelayout();
190
191       // As the font might change, recalculate the handle positions is needed.
192       controller.mImpl->mEventData->mUpdateLeftSelectionPosition  = true;
193       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
194       controller.mImpl->mEventData->mUpdateHighlightBox           = true;
195       controller.mImpl->mEventData->mScrollAfterUpdatePosition    = true;
196     }
197   }
198 }
199
200 bool Controller::InputFontHandler::IsInputFontWeightDefined(const Controller& controller)
201 {
202   bool defined = false;
203
204   if(NULL != controller.mImpl->mEventData)
205   {
206     defined = controller.mImpl->mEventData->mInputStyle.isWeightDefined;
207   }
208
209   return defined;
210 }
211
212 FontWeight Controller::InputFontHandler::GetInputFontWeight(const Controller& controller)
213 {
214   if(NULL != controller.mImpl->mEventData)
215   {
216     return controller.mImpl->mEventData->mInputStyle.weight;
217   }
218
219   return controller.GetDefaultFontWeight();
220 }
221
222 void Controller::InputFontHandler::SetInputFontWidth(Controller& controller, FontWidth width)
223 {
224   if(NULL != controller.mImpl->mEventData)
225   {
226     controller.mImpl->mEventData->mInputStyle.width          = width;
227     controller.mImpl->mEventData->mInputStyle.isWidthDefined = true;
228
229     if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
230     {
231       CharacterIndex startOfSelectedText  = 0u;
232       Length         lengthOfSelectedText = 0u;
233
234       if(EventData::SELECTING == controller.mImpl->mEventData->mState)
235       {
236         // Update a font description run for the selecting state.
237         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
238                                                                              controller.mImpl->mModel->mLogicalModel,
239                                                                              startOfSelectedText,
240                                                                              lengthOfSelectedText);
241
242         fontDescriptionRun.width        = width;
243         fontDescriptionRun.widthDefined = true;
244
245         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
246         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
247         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
248       }
249       else
250       {
251         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
252         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
253         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = controller.mImpl->mModel->mLogicalModel->mText.Count();
254       }
255
256       // Request to relayout.
257       controller.mImpl->mOperationsPending      = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
258                                                                          VALIDATE_FONTS |
259                                                                          SHAPE_TEXT |
260                                                                          GET_GLYPH_METRICS |
261                                                                          LAYOUT |
262                                                                          UPDATE_LAYOUT_SIZE |
263                                                                          REORDER |
264                                                                          ALIGN);
265       controller.mImpl->mRecalculateNaturalSize = true;
266       controller.mImpl->RequestRelayout();
267
268       // As the font might change, recalculate the handle positions is needed.
269       controller.mImpl->mEventData->mUpdateLeftSelectionPosition  = true;
270       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
271       controller.mImpl->mEventData->mUpdateHighlightBox           = true;
272       controller.mImpl->mEventData->mScrollAfterUpdatePosition    = true;
273     }
274   }
275 }
276
277 bool Controller::InputFontHandler::IsInputFontWidthDefined(const Controller& controller)
278 {
279   bool defined = false;
280
281   if(NULL != controller.mImpl->mEventData)
282   {
283     defined = controller.mImpl->mEventData->mInputStyle.isWidthDefined;
284   }
285
286   return defined;
287 }
288
289 FontWidth Controller::InputFontHandler::GetInputFontWidth(const Controller& controller)
290 {
291   if(NULL != controller.mImpl->mEventData)
292   {
293     return controller.mImpl->mEventData->mInputStyle.width;
294   }
295
296   return controller.GetDefaultFontWidth();
297 }
298
299 void Controller::InputFontHandler::SetInputFontSlant(Controller& controller, FontSlant slant)
300 {
301   if(NULL != controller.mImpl->mEventData)
302   {
303     controller.mImpl->mEventData->mInputStyle.slant          = slant;
304     controller.mImpl->mEventData->mInputStyle.isSlantDefined = true;
305
306     if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
307     {
308       CharacterIndex startOfSelectedText  = 0u;
309       Length         lengthOfSelectedText = 0u;
310
311       if(EventData::SELECTING == controller.mImpl->mEventData->mState)
312       {
313         // Update a font description run for the selecting state.
314         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
315                                                                              controller.mImpl->mModel->mLogicalModel,
316                                                                              startOfSelectedText,
317                                                                              lengthOfSelectedText);
318
319         fontDescriptionRun.slant        = slant;
320         fontDescriptionRun.slantDefined = true;
321
322         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
323         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
324         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
325       }
326       else
327       {
328         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
329         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
330         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = controller.mImpl->mModel->mLogicalModel->mText.Count();
331       }
332
333       // Request to relayout.
334       controller.mImpl->mOperationsPending      = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
335                                                                          VALIDATE_FONTS |
336                                                                          SHAPE_TEXT |
337                                                                          GET_GLYPH_METRICS |
338                                                                          LAYOUT |
339                                                                          UPDATE_LAYOUT_SIZE |
340                                                                          REORDER |
341                                                                          ALIGN);
342       controller.mImpl->mRecalculateNaturalSize = true;
343       controller.mImpl->RequestRelayout();
344
345       // As the font might change, recalculate the handle positions is needed.
346       controller.mImpl->mEventData->mUpdateLeftSelectionPosition  = true;
347       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
348       controller.mImpl->mEventData->mUpdateHighlightBox           = true;
349       controller.mImpl->mEventData->mScrollAfterUpdatePosition    = true;
350     }
351   }
352 }
353
354 bool Controller::InputFontHandler::IsInputFontSlantDefined(const Controller& controller)
355 {
356   bool defined = false;
357
358   if(NULL != controller.mImpl->mEventData)
359   {
360     defined = controller.mImpl->mEventData->mInputStyle.isSlantDefined;
361   }
362
363   return defined;
364 }
365
366 FontSlant Controller::InputFontHandler::GetInputFontSlant(const Controller& controller)
367 {
368   if(NULL != controller.mImpl->mEventData)
369   {
370     return controller.mImpl->mEventData->mInputStyle.slant;
371   }
372
373   return controller.GetDefaultFontSlant();
374 }
375
376 void Controller::InputFontHandler::SetInputFontPointSize(Controller& controller, float size)
377 {
378   if(NULL != controller.mImpl->mEventData)
379   {
380     controller.mImpl->mEventData->mInputStyle.size          = size;
381     controller.mImpl->mEventData->mInputStyle.isSizeDefined = true;
382
383     if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
384     {
385       CharacterIndex startOfSelectedText  = 0u;
386       Length         lengthOfSelectedText = 0u;
387
388       if(EventData::SELECTING == controller.mImpl->mEventData->mState)
389       {
390         // Update a font description run for the selecting state.
391         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
392                                                                              controller.mImpl->mModel->mLogicalModel,
393                                                                              startOfSelectedText,
394                                                                              lengthOfSelectedText);
395
396         fontDescriptionRun.size        = static_cast<PointSize26Dot6>(size * controller.mImpl->GetFontSizeScale() * 64.f);
397         fontDescriptionRun.sizeDefined = true;
398
399         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
400         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
401         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
402       }
403       else
404       {
405         controller.mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
406         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
407         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = controller.mImpl->mModel->mLogicalModel->mText.Count();
408       }
409
410       // Request to relayout.
411       controller.mImpl->mOperationsPending      = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
412                                                                          VALIDATE_FONTS |
413                                                                          SHAPE_TEXT |
414                                                                          GET_GLYPH_METRICS |
415                                                                          LAYOUT |
416                                                                          UPDATE_LAYOUT_SIZE |
417                                                                          REORDER |
418                                                                          ALIGN);
419       controller.mImpl->mRecalculateNaturalSize = true;
420       controller.mImpl->RequestRelayout();
421
422       // As the font might change, recalculate the handle positions is needed.
423       controller.mImpl->mEventData->mUpdateLeftSelectionPosition  = true;
424       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
425       controller.mImpl->mEventData->mUpdateHighlightBox           = true;
426       controller.mImpl->mEventData->mScrollAfterUpdatePosition    = true;
427     }
428   }
429 }
430
431 float Controller::InputFontHandler::GetInputFontPointSize(const Controller& controller)
432 {
433   if(NULL != controller.mImpl->mEventData)
434   {
435     return controller.mImpl->mEventData->mInputStyle.size;
436   }
437
438   // Return the default font's point size if there is no EventData.
439   return controller.GetDefaultFontSize(Text::Controller::POINT_SIZE);
440 }
441 } // namespace Text
442
443 } // namespace Toolkit
444
445 } // namespace Dali