Merge "[ATSPI] Implementation of Hypertext and Hyperlink in text controls" into devel...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / common-text-utils.cpp
1 /*
2  * Copyright (c) 2021 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 #include <dali/public-api/actors/layer.h>
18
19 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
20 #include <dali-toolkit/devel-api/controls/control-devel.h>
21 #include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
22 #include <dali-toolkit/internal/text/text-view.h>
23
24 namespace Dali::Toolkit::Internal
25 {
26 void CommonTextUtils::SynchronizeTextAnchorsInParent(
27   Actor                             parent,
28   Text::ControllerPtr               controller,
29   std::vector<Toolkit::TextAnchor>& anchorActors)
30 {
31   for(auto& anchorActor : anchorActors)
32   {
33     parent.Remove(anchorActor);
34   }
35   if(Dali::Accessibility::IsUp())
36   {
37     controller->GetAnchorActors(anchorActors);
38     for(auto& anchorActor : anchorActors)
39     {
40       parent.Add(anchorActor);
41     }
42   }
43 }
44
45 void CommonTextUtils::RenderText(
46   Actor                             textActor,
47   Text::RendererPtr                 renderer,
48   Text::ControllerPtr               controller,
49   Text::DecoratorPtr                decorator,
50   float&                            alignmentOffset,
51   Actor&                            renderableActor,
52   Actor&                            backgroundActor,
53   Toolkit::Control&                 stencil,
54   std::vector<Actor>&               clippingDecorationActors,
55   std::vector<Toolkit::TextAnchor>& anchorActors,
56   Text::Controller::UpdateTextType  updateTextType)
57 {
58   Actor newRenderableActor;
59
60   if(Text::Controller::NONE_UPDATED != (Text::Controller::MODEL_UPDATED & updateTextType))
61   {
62     if(renderer)
63     {
64       newRenderableActor = renderer->Render(controller->GetView(),
65                                             textActor,
66                                             Property::INVALID_INDEX, // Animatable property not supported
67                                             alignmentOffset,
68                                             DepthIndex::CONTENT);
69     }
70
71     if(renderableActor != newRenderableActor)
72     {
73       UnparentAndReset(backgroundActor);
74       UnparentAndReset(renderableActor);
75       renderableActor = newRenderableActor;
76
77       if(renderableActor)
78       {
79         backgroundActor = controller->CreateBackgroundActor();
80       }
81     }
82   }
83
84   if(renderableActor)
85   {
86     const Vector2& scrollOffset = controller->GetTextModel()->GetScrollPosition();
87
88     float renderableActorPositionX, renderableActorPositionY;
89
90     if(stencil)
91     {
92       renderableActorPositionX = scrollOffset.x + alignmentOffset;
93       renderableActorPositionY = scrollOffset.y;
94     }
95     else
96     {
97       Extents padding;
98       padding = textActor.GetProperty<Extents>(Toolkit::Control::Property::PADDING);
99
100       // Support Right-To-Left of padding
101       Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(textActor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
102       if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
103       {
104         std::swap(padding.start, padding.end);
105       }
106
107       renderableActorPositionX = scrollOffset.x + alignmentOffset + padding.start;
108       renderableActorPositionY = scrollOffset.y + padding.top;
109     }
110
111     renderableActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY));
112
113     // Make sure the actors are parented correctly with/without clipping
114     Actor self = stencil ? stencil : textActor;
115
116     Actor highlightActor;
117
118     for(std::vector<Actor>::iterator it    = clippingDecorationActors.begin(),
119                                      endIt = clippingDecorationActors.end();
120         it != endIt;
121         ++it)
122     {
123       self.Add(*it);
124       it->LowerToBottom();
125
126       if(it->GetProperty<std::string>(Dali::Actor::Property::NAME) == "HighlightActor")
127       {
128         highlightActor = *it;
129       }
130     }
131     clippingDecorationActors.clear();
132
133     self.Add(renderableActor);
134
135     if(backgroundActor)
136     {
137       if(decorator && decorator->IsHighlightVisible())
138       {
139         self.Add(backgroundActor);
140         backgroundActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY)); // In text field's coords.
141         backgroundActor.LowerBelow(highlightActor);
142       }
143       else
144       {
145         renderableActor.Add(backgroundActor);
146         backgroundActor.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f)); // In renderable actor's coords.
147         backgroundActor.LowerToBottom();
148       }
149     }
150     SynchronizeTextAnchorsInParent(textActor, controller, anchorActors);
151   }
152 }
153
154 } // namespace Dali::Toolkit::Internal