[dali_1.2.6] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
1 /*
2  * Copyright (c) 2016 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/internal/event/events/hit-test-algorithm-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/system-overlay.h>
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/public-api/math/vector2.h>
25 #include <dali/public-api/math/vector4.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/internal/event/actors/actor-impl.h>
28 #include <dali/internal/event/actors/camera-actor-impl.h>
29 #include <dali/internal/event/actors/layer-impl.h>
30 #include <dali/internal/event/actors/layer-list.h>
31 #include <dali/internal/event/common/system-overlay-impl.h>
32 #include <dali/internal/event/common/stage-impl.h>
33 #include <dali/internal/event/common/projection.h>
34 #include <dali/internal/event/images/frame-buffer-image-impl.h>
35 #include <dali/internal/event/render-tasks/render-task-impl.h>
36 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
37
38 namespace Dali
39 {
40
41 namespace Internal
42 {
43
44 namespace HitTestAlgorithm
45 {
46
47 namespace
48 {
49
50 struct HitActor
51 {
52   HitActor()
53   : actor( NULL ),
54     distance( std::numeric_limits<float>::max() ),
55     depth( std::numeric_limits<int>::min() )
56   {
57   }
58
59   Actor *actor;                         ///< The actor hit (if actor is hit, then this is initialised).
60   Vector2 hitPosition;                  ///< Position of hit (only valid if actor valid).
61   float distance;                       ///< Distance from ray origin to hit actor.
62   int depth;                            ///< Depth index of this actor.
63 };
64
65 /**
66  * Creates an Actor handle so that a HitTestFunction provided via the public API can be called.
67  */
68 struct HitTestFunctionWrapper : public HitTestInterface
69 {
70   /**
71    * Constructor
72    *
73    * @param[in] func HitTestFunction to call with an Actor handle.
74    */
75   HitTestFunctionWrapper( Dali::HitTestAlgorithm::HitTestFunction func )
76   : mFunc( func )
77   {
78   }
79
80   virtual bool IsActorHittable( Actor* actor )
81   {
82     return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::CHECK_ACTOR );
83   }
84
85   virtual bool DescendActorHierarchy( Actor* actor )
86   {
87     return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE );
88   }
89
90   virtual bool DoesLayerConsumeHit( Layer* layer )
91   {
92     // Layer::IsTouchConsumed() focuses on touch only. Here we are a wrapper for the public-api
93     // where the caller may want to check for something completely different.
94     // TODO: Should provide a means to let caller decide. For now do not allow layers to consume
95     return false;
96   }
97
98   Dali::HitTestAlgorithm::HitTestFunction mFunc;
99 };
100
101 /**
102  * Used in the hit-test algorithm to check whether the actor is touchable.
103  * It is used by the touch event processor.
104  */
105 struct ActorTouchableCheck : public HitTestInterface
106 {
107   virtual bool IsActorHittable( Actor* actor )
108   {
109     return actor->GetTouchRequired() && // Does the Application or derived actor type require a touch event?
110            actor->IsHittable();         // Is actor sensitive, visible and on the scene?
111   }
112
113   virtual bool DescendActorHierarchy( Actor* actor )
114   {
115     return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
116            actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
117   }
118
119   virtual bool DoesLayerConsumeHit( Layer* layer )
120   {
121     return layer->IsTouchConsumed();
122   }
123 };
124
125 /**
126  * Check to see if the actor we're about to hit test is exclusively owned by another rendertask?
127  */
128 bool IsActorExclusiveToAnotherRenderTask( const Actor& actor,
129                                           const RenderTask& renderTask,
130                                           const Vector< RenderTaskList::Exclusive >& exclusives )
131
132 {
133   if( exclusives.Size() )
134   {
135     for( Vector< RenderTaskList::Exclusive >::Iterator exclusiveIt = exclusives.Begin(); exclusives.End() != exclusiveIt; ++exclusiveIt )
136     {
137       if( ( exclusiveIt->renderTaskPtr != &renderTask ) && ( exclusiveIt->actorPtr == &actor ) )
138       {
139         return true;
140       }
141     }
142   }
143   return false;
144 }
145
146 /**
147  * Recursively hit test all the actors, without crossing into other layers.
148  * This algorithm performs a Depth-First-Search (DFS) on all Actors within Layer.
149  * Hit-Testing each Actor, noting the distance from the Ray-Origin (3D origin
150  * of touch vector). The closest Hit-Tested Actor is that which is returned.
151  * Exceptions to this rule are:
152  * - When comparing against renderable parents, if Actor is the same distance
153  * or closer than it's renderable parent, then it takes priority.
154  */
155 HitActor HitTestWithinLayer( Actor& actor,
156                              const RenderTask& renderTask,
157                              const Vector< RenderTaskList::Exclusive >& exclusives,
158                              const Vector4& rayOrigin,
159                              const Vector4& rayDir,
160                              float& nearClippingPlane,
161                              float& farClippingPlane,
162                              HitTestInterface& hitCheck,
163                              bool& overlayHit,
164                              bool layerIs3d,
165                              unsigned int clippingDepth,
166                              unsigned int clippingBitPlaneMask )
167 {
168   HitActor hit;
169
170   if( IsActorExclusiveToAnotherRenderTask( actor, renderTask, exclusives ) )
171   {
172     return hit;
173   }
174
175   // For clipping, regardless of whether we have hit this actor or not,
176   // we increase the clipping depth if we have hit a clipping actor.
177   // This is used later to ensure all nested clipped children have hit
178   // all clipping actors also for them to be counted as hit.
179   unsigned int newClippingDepth = clippingDepth;
180   bool clippingActor = actor.GetClippingMode() != ClippingMode::DISABLED;
181   if( clippingActor )
182   {
183     ++newClippingDepth;
184   }
185
186   // If we are a clipping actor or hittable...
187   if( clippingActor || hitCheck.IsActorHittable( &actor ) )
188   {
189     Vector3 size( actor.GetCurrentSize() );
190
191     // Ensure the actor has a valid size.
192     // If so, perform a quick ray sphere test to see if our ray is close to the actor.
193     if( size.x > 0.0f && size.y > 0.0f && actor.RaySphereTest( rayOrigin, rayDir ) )
194     {
195       Vector2 hitPointLocal;
196       float distance;
197
198       // Finally, perform a more accurate ray test to see if our ray actually hits the actor.
199       if( actor.RayActorTest( rayOrigin, rayDir, hitPointLocal, distance ) )
200       {
201         if( distance >= nearClippingPlane && distance <= farClippingPlane )
202         {
203           // If the hit has happened on a clipping actor, then add this clipping depth to the mask of hit clipping depths.
204           // This mask shows all the actors that have been hit at different clipping depths.
205           if( clippingActor )
206           {
207             clippingBitPlaneMask |= 1u << clippingDepth;
208           }
209
210           if( overlayHit && !actor.IsOverlay() )
211           {
212             // If we have already hit an overlay and current actor is not an overlay ignore current actor.
213           }
214           else
215           {
216             if( actor.IsOverlay() )
217             {
218               overlayHit = true;
219             }
220
221             // At this point we have hit an actor.
222             // Now perform checks for clipping.
223             // Assume we have hit the actor first as if it is not clipped this would be the case.
224             bool haveHitActor = true;
225
226             // Check if we are performing clipping. IE. if any actors so far have clipping enabled - not necessarily this one.
227             // We can do this by checking the clipping depth has a value 1 or above.
228             if( newClippingDepth >= 1u )
229             {
230               // Now for us to count this actor as hit, we must have also hit
231               // all CLIPPING actors up to this point in the hierarchy as well.
232               // This information is stored in the clippingBitPlaneMask we updated above.
233               // Here we calculate a comparison mask by setting all the bits up to the current depth value.
234               // EG. a depth of 4 (10000 binary) = a mask of 1111 binary.
235               // This allows us a fast way of comparing all bits are set up to this depth.
236               unsigned int clippingDepthMask = ( 1u << clippingDepth ) - 1u;
237
238               // The two masks must be equal to be a hit, as we are already assuming a hit
239               // (for non-clipping mode) then they must be not-equal to disqualify the hit.
240               if( clippingBitPlaneMask != clippingDepthMask )
241               {
242                 haveHitActor = false;
243               }
244             }
245
246             if( haveHitActor )
247             {
248               hit.actor = &actor;
249               hit.hitPosition = hitPointLocal;
250               hit.distance = distance;
251               hit.depth = actor.GetHierarchyDepth() * Dali::Layer::TREE_DEPTH_MULTIPLIER;
252
253               if( actor.GetRendererCount() > 0 )
254               {
255                 //Get renderer with maximum depth
256                 int rendererMaxDepth(actor.GetRendererAt( 0 ).Get()->GetDepthIndex());
257                 for( unsigned int i(1); i < actor.GetRendererCount(); ++i )
258                 {
259                   int depth = actor.GetRendererAt( i ).Get()->GetDepthIndex();
260                   if( depth > rendererMaxDepth )
261                   {
262                     rendererMaxDepth = depth;
263                   }
264                 }
265                 hit.depth += rendererMaxDepth;
266               }
267             }
268           }
269         }
270       }
271     }
272   }
273
274   // Find a child hit, until we run out of actors in the current layer.
275   HitActor childHit;
276   if( actor.GetChildCount() > 0 )
277   {
278     childHit.distance = std::numeric_limits<float>::max();
279     childHit.depth = std::numeric_limits<int>::min();
280     ActorContainer& children = actor.GetChildrenInternal();
281
282     // Hit test ALL children and calculate their distance.
283     bool parentIsRenderable = actor.IsRenderable();
284
285     for( ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter )
286     {
287       // Descend tree only if...
288       if ( !( *iter )->IsLayer() &&                                 // Child is NOT a layer, hit testing current layer only
289             ( hitCheck.DescendActorHierarchy( ( *iter ).Get() ) ) ) // We can descend into child hierarchy
290       {
291         HitActor currentHit( HitTestWithinLayer( ( *iter->Get() ),
292                                                  renderTask,
293                                                  exclusives,
294                                                  rayOrigin,
295                                                  rayDir,
296                                                  nearClippingPlane,
297                                                  farClippingPlane,
298                                                  hitCheck,
299                                                  overlayHit,
300                                                  layerIs3d,
301                                                  newClippingDepth,
302                                                  clippingBitPlaneMask ) );
303
304         bool updateChildHit = false;
305         if( currentHit.distance >= 0.0f )
306         {
307           if( layerIs3d )
308           {
309             updateChildHit = ( ( currentHit.depth > childHit.depth ) ||
310                                ( ( currentHit.depth == childHit.depth ) && ( currentHit.distance < childHit.distance ) ) );
311           }
312           else
313           {
314             updateChildHit = currentHit.depth >= childHit.depth;
315           }
316         }
317
318         if( updateChildHit )
319         {
320           if( !parentIsRenderable || currentHit.depth > hit.depth ||
321             ( layerIs3d && ( currentHit.depth == hit.depth && currentHit.distance < hit.distance )) )
322           {
323             childHit = currentHit;
324           }
325         }
326       }
327     }
328   }
329
330   return ( childHit.actor ) ? childHit : hit;
331 }
332
333 /**
334  * Return true if actor is sourceActor or a descendent of sourceActor
335  */
336 bool IsWithinSourceActors( const Actor& sourceActor, const Actor& actor )
337 {
338   if ( &sourceActor == &actor )
339   {
340     return true;
341   }
342
343   Actor* parent = actor.GetParent();
344   if ( parent )
345   {
346     return IsWithinSourceActors( sourceActor, *parent );
347   }
348
349   // Not within source actors
350   return false;
351 }
352
353 /**
354  * Returns true if the layer and all of the layer's parents are visible and sensitive.
355  */
356 inline bool IsActuallyHittable( Layer& layer, const Vector2& screenCoordinates, const Vector2& stageSize, HitTestInterface& hitCheck )
357 {
358   bool hittable( true );
359
360   if( layer.IsClipping() )
361   {
362     ClippingBox box = layer.GetClippingBox();
363
364     if( screenCoordinates.x < box.x ||
365         screenCoordinates.x > box.x + box.width ||
366         screenCoordinates.y < stageSize.y - (box.y + box.height) ||
367         screenCoordinates.y > stageSize.y - box.y)
368     {
369       // Not touchable if clipping is enabled in the layer and the screen coordinate is outside the clip region.
370       hittable = false;
371     }
372   }
373
374   if( hittable )
375   {
376     Actor* actor( &layer );
377
378     // Ensure that we can descend into the layer's (or any of its parent's) hierarchy.
379     while( actor && hittable )
380     {
381       if( ! hitCheck.DescendActorHierarchy( actor ) )
382       {
383         hittable = false;
384         break;
385       }
386       actor = actor->GetParent();
387     }
388   }
389
390   return hittable;
391 }
392
393 /**
394  * Gets the near and far clipping planes of the camera from which the scene is viewed in the render task.
395  */
396 void GetCameraClippingPlane( RenderTask& renderTask, float& nearClippingPlane, float& farClippingPlane )
397 {
398   CameraActor* cameraActor = renderTask.GetCameraActor();
399   nearClippingPlane = cameraActor->GetNearClippingPlane();
400   farClippingPlane = cameraActor->GetFarClippingPlane();
401 }
402
403 /**
404  * Hit test a RenderTask
405  */
406 bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
407                         Stage& stage,
408                         LayerList& layers,
409                         RenderTask& renderTask,
410                         Vector2 screenCoordinates,
411                         Results& results,
412                         HitTestInterface& hitCheck )
413 {
414   if ( renderTask.IsHittable( screenCoordinates ) )
415   {
416     Viewport viewport;
417     renderTask.GetViewport( viewport );
418     if( screenCoordinates.x < viewport.x ||
419         screenCoordinates.x > viewport.x + viewport.width ||
420         screenCoordinates.y < viewport.y ||
421         screenCoordinates.y > viewport.y + viewport.height )
422     {
423       // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
424       return false;
425     }
426
427     float nearClippingPlane, farClippingPlane;
428     GetCameraClippingPlane( renderTask, nearClippingPlane, farClippingPlane );
429
430     // Determine the layer depth of the source actor
431     Actor* sourceActor( renderTask.GetSourceActor() );
432     if( sourceActor )
433     {
434       Dali::Layer layer( sourceActor->GetLayer() );
435       if( layer )
436       {
437         const unsigned int sourceActorDepth( layer.GetDepth() );
438
439         CameraActor* cameraActor = renderTask.GetCameraActor();
440         bool pickingPossible = cameraActor->BuildPickingRay(
441             screenCoordinates,
442             viewport,
443             results.rayOrigin,
444             results.rayDirection );
445         if( !pickingPossible )
446         {
447           return false;
448         }
449
450         // Hit test starting with the top layer, working towards the bottom layer.
451         HitActor hit;
452         bool overlayHit = false;
453         bool layerConsumesHit = false;
454         const Vector2& stageSize = stage.GetSize();
455
456         for( int i = layers.GetLayerCount() - 1; i >= 0 && !( hit.actor ); --i )
457         {
458           Layer* layer( layers.GetLayer( i ) );
459           overlayHit = false;
460
461           // Ensure layer is touchable (also checks whether ancestors are also touchable)
462           if( IsActuallyHittable( *layer, screenCoordinates, stageSize, hitCheck ) )
463           {
464             // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy
465             if( sourceActorDepth == static_cast<unsigned int>( i ) )
466             {
467               // Recursively hit test the source actor & children, without crossing into other layers.
468               hit = HitTestWithinLayer( *sourceActor,
469                                         renderTask,
470                                         exclusives,
471                                         results.rayOrigin,
472                                         results.rayDirection,
473                                         nearClippingPlane,
474                                         farClippingPlane,
475                                         hitCheck,
476                                         overlayHit,
477                                         layer->GetBehavior() == Dali::Layer::LAYER_3D,
478                                         0u,
479                                         0u );
480             }
481             else if( IsWithinSourceActors( *sourceActor, *layer ) )
482             {
483               // Recursively hit test all the actors, without crossing into other layers.
484               hit = HitTestWithinLayer( *layer,
485                                         renderTask,
486                                         exclusives,
487                                         results.rayOrigin,
488                                         results.rayDirection,
489                                         nearClippingPlane,
490                                         farClippingPlane,
491                                         hitCheck,
492                                         overlayHit,
493                                         layer->GetBehavior() == Dali::Layer::LAYER_3D,
494                                         0u,
495                                         0u );
496             }
497
498             // If this layer is set to consume the hit, then do not check any layers behind it
499             if( hitCheck.DoesLayerConsumeHit( layer ) )
500             {
501               layerConsumesHit = true;
502               break;
503             }
504           }
505         }
506
507         if( hit.actor )
508         {
509           results.renderTask = Dali::RenderTask( &renderTask );
510           results.actor = Dali::Actor( hit.actor );
511           results.actorCoordinates = hit.hitPosition;
512
513           return true; // Success
514         }
515
516         if( layerConsumesHit )
517         {
518           return true; // Also success if layer is consuming the hit
519         }
520       }
521     }
522   }
523   return false;
524 }
525
526 /**
527  * Iterate through the RenderTaskList and perform hit testing.
528  *
529  * @param[in] stage The stage the tests will be performed in
530  * @param[in] layers The list of layers to test
531  * @param[in] taskList The list of render tasks
532  * @param[out] results Ray information calculated by the camera
533  * @param[in] hitCheck The hit testing interface object to use
534  * @param[in] onScreen True to test on-screen, false to test off-screen
535  * @return True if we have a hit, false otherwise
536  */
537 bool HitTestRenderTaskList( Stage& stage,
538                             LayerList& layers,
539                             RenderTaskList& taskList,
540                             const Vector2& screenCoordinates,
541                             Results& results,
542                             HitTestInterface& hitCheck,
543                             bool onScreen )
544 {
545   RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
546   RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
547   const Vector< RenderTaskList::Exclusive >& exclusives = taskList.GetExclusivesList();
548
549   for( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter )
550   {
551     RenderTask& renderTask = GetImplementation( *iter );
552     Dali::FrameBufferImage frameBufferImage = renderTask.GetTargetFrameBuffer();
553
554     // Note that if frameBufferImage is NULL we are using the default (on screen) render target
555     if( frameBufferImage )
556     {
557       ResourceId id = GetImplementation( frameBufferImage ).GetResourceId();
558
559       // Change comparison depending on if on-screen or off-screen.
560       if( onScreen ? ( 0 != id ) : ( 0 == id ) )
561       {
562         // Skip to next task
563         continue;
564       }
565     }
566
567     if( HitTestRenderTask( exclusives, stage, layers, renderTask, screenCoordinates, results, hitCheck ) )
568     {
569       // Return true when an actor is hit (or layer in our render-task consumes the hit)
570       return true; // don't bother checking off screen tasks
571     }
572   }
573
574   return false;
575 }
576
577 /**
578  * Iterate through the RenderTaskList and perform hit testing for both on-screen and off-screen.
579  *
580  * @param[in] stage The stage the tests will be performed in
581  * @param[in] layers The list of layers to test
582  * @param[in] taskList The list of render tasks
583  * @param[out] results Ray information calculated by the camera
584  * @param[in] hitCheck The hit testing interface object to use
585  * @param[in] onScreen True to test on-screen, false to test off-screen
586  * @return True if we have a hit, false otherwise
587  */
588 bool HitTestForEachRenderTask( Stage& stage,
589                                LayerList& layers,
590                                RenderTaskList& taskList,
591                                const Vector2& screenCoordinates,
592                                Results& results,
593                                HitTestInterface& hitCheck )
594 {
595   bool result = false;
596
597   // Check on-screen tasks before off-screen ones.
598   // Hit test order should be reverse of draw order (see ProcessRenderTasks() where off-screen tasks are drawn first).
599   if( HitTestRenderTaskList( stage, layers, taskList, screenCoordinates, results, hitCheck, true  ) ||
600       HitTestRenderTaskList( stage, layers, taskList, screenCoordinates, results, hitCheck, false ) )
601   {
602     // Found hit.
603     result = true;
604   }
605
606   return result;
607 }
608
609 } // unnamed namespace
610
611 bool HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
612 {
613   bool wasHit( false );
614   // Hit-test the regular on-stage actors
615   RenderTaskList& taskList = stage.GetRenderTaskList();
616   LayerList& layerList = stage.GetLayerList();
617
618   Results hitTestResults;
619   HitTestFunctionWrapper hitTestFunctionWrapper( func );
620   if( HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
621   {
622     results.actor = hitTestResults.actor;
623     results.actorCoordinates = hitTestResults.actorCoordinates;
624     wasHit = true;
625   }
626   return wasHit;
627 }
628
629 bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
630 {
631   bool wasHit( false );
632
633   // Hit-test the system-overlay actors first
634   SystemOverlay* systemOverlay = stage.GetSystemOverlayInternal();
635
636   if( systemOverlay )
637   {
638     RenderTaskList& overlayTaskList = systemOverlay->GetOverlayRenderTasks();
639     LayerList& overlayLayerList = systemOverlay->GetLayerList();
640
641     wasHit = HitTestForEachRenderTask( stage, overlayLayerList, overlayTaskList, screenCoordinates, results, hitTestInterface );
642   }
643
644   // Hit-test the regular on-stage actors
645   if( !wasHit )
646   {
647     RenderTaskList& taskList = stage.GetRenderTaskList();
648     LayerList& layerList = stage.GetLayerList();
649
650     wasHit = HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, results, hitTestInterface );
651   }
652   return wasHit;
653 }
654
655 bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results )
656 {
657   ActorTouchableCheck actorTouchableCheck;
658   return HitTest( stage, screenCoordinates, results, actorTouchableCheck );
659 }
660
661 bool HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordinates,
662               Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
663 {
664   bool wasHit( false );
665   Results hitTestResults;
666
667   const Vector< RenderTaskList::Exclusive >& exclusives = stage.GetRenderTaskList().GetExclusivesList();
668   HitTestFunctionWrapper hitTestFunctionWrapper( func );
669   if( HitTestRenderTask( exclusives, stage, stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
670   {
671     results.actor = hitTestResults.actor;
672     results.actorCoordinates = hitTestResults.actorCoordinates;
673     wasHit = true;
674   }
675   return wasHit;
676 }
677
678
679 } // namespace HitTestAlgorithm
680
681 } // namespace Internal
682
683 } // namespace Dali