(AutomatedTests) Merged managed & unmanaged tests
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / utc-Dali-HitTestAlgorithm.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 #include <iostream>
19
20 #include <stdlib.h>
21 #include <dali/public-api/dali-core.h>
22 #include <dali/integration-api/events/touch-event-integ.h>
23 #include <dali-test-suite-utils.h>
24
25 using namespace Dali;
26
27 namespace
28 {
29
30 /**
31  * The functor to be used in the hit-test algorithm to check whether the actor is hittable.
32  */
33 bool IsActorHittableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
34 {
35   bool hittable = false;
36
37   switch (type)
38   {
39     case Dali::HitTestAlgorithm::CHECK_ACTOR:
40     {
41       // Check whether the actor is visible and not fully transparent.
42       if( actor.IsVisible()
43        && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
44       {
45         // Check whether the actor has the specific name "HittableActor"
46         if(actor.GetName() == "HittableActor")
47         {
48           hittable = true;
49         }
50       }
51       break;
52     }
53     case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
54     {
55       if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
56       {
57         hittable = true;
58       }
59       break;
60     }
61     default:
62     {
63       break;
64     }
65   }
66
67   return hittable;
68 };
69
70
71 bool DefaultIsActorTouchableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
72 {
73   bool hittable = false;
74
75   switch (type)
76   {
77     case Dali::HitTestAlgorithm::CHECK_ACTOR:
78     {
79       if( actor.IsVisible() &&
80           actor.IsSensitive() &&
81           actor.GetCurrentWorldColor().a > 0.01f)
82       {
83         hittable = true;
84       }
85       break;
86     }
87     case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
88     {
89       if( actor.IsVisible() && // Actor is visible, if not visible then none of its children are visible.
90           actor.IsSensitive()) // Actor is sensitive, if insensitive none of its children should be hittable either.
91       {
92         hittable = true;
93       }
94       break;
95     }
96     default:
97     {
98       break;
99     }
100   }
101
102   return hittable;
103 };
104
105 } // anonymous namespace
106
107
108 // Positive test case for a method
109 int UtcDaliHitTestAlgorithmWithFunctor(void)
110 {
111   TestApplication application;
112   tet_infoline("Testing Dali::HitTestAlgorithm functor");
113
114   Stage stage = Stage::GetCurrent();
115
116   Actor actor = Actor::New();
117   actor.SetSize(100.0f, 100.0f);
118   actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
119   actor.SetName("NonHittableActor");
120   stage.Add(actor);
121
122   // Render and notify
123   application.SendNotification();
124   application.Render();
125
126   Vector2 screenCoordinates( 10.0f, 10.0f );
127   Vector2 localCoordinates;
128   actor.ScreenToLocal( localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y );
129
130   // Perform a hit-test at the given screen coordinates
131   Dali::HitTestAlgorithm::Results results;
132   Dali::HitTestAlgorithm::HitTest( stage, screenCoordinates, results, IsActorHittableFunction );
133   DALI_TEST_CHECK( results.actor != actor );
134
135   actor.SetName("HittableActor");
136
137   results.actor = Actor();
138   results.actorCoordinates = Vector2::ZERO;
139
140   // Perform a hit-test at the given screen coordinates
141   Dali::HitTestAlgorithm::HitTest( stage, screenCoordinates, results, IsActorHittableFunction );
142   DALI_TEST_CHECK( results.actor == actor );
143   DALI_TEST_EQUALS( localCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION );
144   END_TEST;
145 }
146
147 int UtcDaliHitTestAlgorithmWithFunctorOnRenderTask(void)
148 {
149   TestApplication application;
150   tet_infoline("Testing Dali::HitTestAlgorithm functor, specific to a given render task");
151
152   Stage stage = Stage::GetCurrent();
153   Size stageSize = stage.GetSize();
154   RenderTaskList taskList = stage.GetRenderTaskList();
155
156   Actor actor[2];
157
158   for( int i=0; i<2; i++ )
159   {
160     actor[i] = Actor::New();
161     actor[i].SetSize(100.f, 100.f);
162     actor[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
163     actor[i].SetAnchorPoint(AnchorPoint::TOP_LEFT);
164     actor[i].SetName("HittableActor");
165     stage.Add(actor[i]);
166   }
167   Vector2 position( 50.f, 40.f );
168   actor[1].SetPosition( position.x, position.y );
169
170   RenderTask renderTask[2];
171   renderTask[0] = taskList.GetTask( 0u );
172
173   FrameBufferImage frameBufferImage =  FrameBufferImage::New(stageSize.width, stageSize.height, Pixel::A8, Image::Never);
174   renderTask[1] = taskList.CreateTask();
175   renderTask[1].SetSourceActor( actor[1] );
176   renderTask[1].SetExclusive( true );
177   renderTask[1].SetInputEnabled( true );
178   renderTask[1].SetTargetFrameBuffer( frameBufferImage );
179   renderTask[1].SetRefreshRate( RenderTask::REFRESH_ONCE );
180   renderTask[1].SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
181   application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
182
183   // Render and notify
184   application.SendNotification();
185   application.Render();
186   application.Render();
187   application.SendNotification();
188
189   // Perform a hit-test at the given screen coordinates with different render tasks
190
191   Dali::HitTestAlgorithm::Results results;
192   Vector2 screenCoordinates( 25.f, 25.f );
193
194   Dali::HitTestAlgorithm::HitTest( renderTask[0], screenCoordinates, results, IsActorHittableFunction );
195   DALI_TEST_CHECK( results.actor == actor[0] );
196   DALI_TEST_EQUALS( screenCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION );
197
198   results.actor = Actor();
199   results.actorCoordinates = Vector2::ZERO;
200   Dali::HitTestAlgorithm::HitTest( renderTask[1], screenCoordinates, results, IsActorHittableFunction );
201   DALI_TEST_CHECK( !results.actor );
202   DALI_TEST_EQUALS( Vector2::ZERO, results.actorCoordinates, 0.1f, TEST_LOCATION );
203
204   screenCoordinates.x = 80.f;
205   screenCoordinates.y = 70.f;
206
207   results.actor = Actor();
208   results.actorCoordinates = Vector2::ZERO;
209   Dali::HitTestAlgorithm::HitTest( renderTask[0], screenCoordinates, results, IsActorHittableFunction );
210   DALI_TEST_CHECK( results.actor == actor[0] );
211   DALI_TEST_EQUALS( screenCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION );
212
213   results.actor = Actor();
214   results.actorCoordinates = Vector2::ZERO;
215   Dali::HitTestAlgorithm::HitTest( renderTask[1], screenCoordinates, results, IsActorHittableFunction );
216   DALI_TEST_CHECK( results.actor == actor[1]);
217   DALI_TEST_EQUALS( screenCoordinates - position, results.actorCoordinates, 0.1f, TEST_LOCATION );
218
219
220   screenCoordinates.x = 120.f;
221   screenCoordinates.y = 130.f;
222
223   results.actor = Actor();
224   results.actorCoordinates = Vector2::ZERO;
225   Dali::HitTestAlgorithm::HitTest( renderTask[0], screenCoordinates, results, IsActorHittableFunction );
226   DALI_TEST_CHECK( results.actor == actor[1] );
227   DALI_TEST_EQUALS( screenCoordinates - position, results.actorCoordinates, 0.1f, TEST_LOCATION );
228
229   results.actor = Actor();
230   results.actorCoordinates = Vector2::ZERO;
231   Dali::HitTestAlgorithm::HitTest( renderTask[1], screenCoordinates, results, IsActorHittableFunction );
232   DALI_TEST_CHECK( results.actor == actor[1]);
233   DALI_TEST_EQUALS( screenCoordinates - position, results.actorCoordinates, 0.1f, TEST_LOCATION );
234   END_TEST;
235 }
236
237
238 int UtcDaliHitTestAlgorithmOrtho01(void)
239 {
240   TestApplication application;
241   tet_infoline("Testing Dali::HitTestAlgorithm with parallel Ortho camera()");
242
243   Stage stage = Stage::GetCurrent();
244   RenderTaskList renderTaskList = stage.GetRenderTaskList();
245   RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
246   Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
247
248   Vector2 stageSize ( stage.GetSize() );
249   cameraActor.SetOrthographicProjection( stageSize );
250   cameraActor.SetPosition(0.0f, 0.0f, 1600.0f);
251
252   Vector2 actorSize( stageSize * 0.5f );
253   // Create two actors with half the size of the stage and set them to be partially overlapping
254   Actor blue = Actor::New();
255   blue.SetName( "Blue" );
256   blue.SetAnchorPoint( AnchorPoint::CENTER );
257   blue.SetParentOrigin( Vector3(1.0f/3.0f, 1.0f/3.0f, 0.5f) );
258   blue.SetSize( actorSize );
259   blue.SetZ(30.0f);
260
261   Actor green = Actor::New( );
262   green.SetName( "Green" );
263   green.SetAnchorPoint( AnchorPoint::CENTER );
264   green.SetParentOrigin( Vector3(2.0f/3.0f, 2.0f/3.0f, 0.5f) );
265   green.SetSize( actorSize );
266
267   // Add the actors to the view
268   stage.Add( blue );
269   stage.Add( green );
270
271   // Render and notify
272   application.SendNotification();
273   application.Render(0);
274   application.Render(10);
275
276   HitTestAlgorithm::Results results;
277   HitTest(stage, Vector2( 240.0f, 400.0f ), results, &DefaultIsActorTouchableFunction);
278   DALI_TEST_CHECK( results.actor == blue );
279   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 5.0f/6.0f, TEST_LOCATION );
280
281   HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction);
282   DALI_TEST_CHECK( results.actor == blue );
283   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
284
285   HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction);
286   DALI_TEST_CHECK( results.actor == green );
287   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
288   END_TEST;
289 }
290
291
292 int UtcDaliHitTestAlgorithmOrtho02(void)
293 {
294   TestApplication application;
295   tet_infoline("Testing Dali::HitTestAlgorithm with offset Ortho camera()");
296
297   Stage stage = Stage::GetCurrent();
298   RenderTaskList renderTaskList = stage.GetRenderTaskList();
299   RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
300   Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
301
302   Vector2 stageSize ( stage.GetSize() );
303   cameraActor.SetOrthographicProjection(-stageSize.x * 0.3f,  stageSize.x * 0.7f,
304                                          stageSize.y * 0.3f, -stageSize.y * 0.7f,
305                                          800.0f, 4895.0f);
306   cameraActor.SetPosition(0.0f, 0.0f, 1600.0f);
307
308   Vector2 actorSize( stageSize * 0.5f );
309   // Create two actors with half the size of the stage and set them to be partially overlapping
310   Actor blue = Actor::New();
311   blue.SetName( "Blue" );
312   blue.SetAnchorPoint( AnchorPoint::TOP_LEFT );
313   blue.SetParentOrigin( Vector3(0.2f, 0.2f, 0.5f) );
314   blue.SetSize( actorSize );
315   blue.SetZ(30.0f);
316
317   Actor green = Actor::New( );
318   green.SetName( "Green" );
319   green.SetAnchorPoint( AnchorPoint::TOP_LEFT );
320   green.SetParentOrigin( Vector3(0.4f, 0.4f, 0.5f) );
321   green.SetSize( actorSize );
322
323   // Add the actors to the view
324   stage.Add( blue );
325   stage.Add( green );
326
327   // Render and notify
328   application.SendNotification();
329   application.Render(0);
330   application.Render(10);
331
332   {
333     HitTestAlgorithm::Results results;
334     HitTest(stage, Vector2( 240.0f, 400.0f ), results, &DefaultIsActorTouchableFunction);
335     DALI_TEST_CHECK( results.actor == green );
336     DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.6f, 0.01f, TEST_LOCATION );
337   }
338
339   {
340     HitTestAlgorithm::Results results;
341     HitTest(stage, Vector2::ZERO, results, &DefaultIsActorTouchableFunction);
342     DALI_TEST_CHECK( results.actor == blue );
343     DALI_TEST_EQUALS( results.actorCoordinates, Vector2::ZERO, TEST_LOCATION );
344   }
345
346   {
347     HitTestAlgorithm::Results results;
348     HitTest(stage, stageSize, results, &DefaultIsActorTouchableFunction);
349     DALI_TEST_CHECK( ! results.actor );
350     DALI_TEST_EQUALS( results.actorCoordinates, Vector2::ZERO, TEST_LOCATION );
351   }
352
353   // Just inside green
354   {
355     HitTestAlgorithm::Results results;
356     HitTest(stage, stageSize*0.69f, results, &DefaultIsActorTouchableFunction);
357     DALI_TEST_CHECK( results.actor == green );
358     DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.98f, 0.01f, TEST_LOCATION );
359   }
360
361   END_TEST;
362 }
363
364 int UtcDaliHitTestAlgorithmStencil(void)
365 {
366   TestApplication application;
367   tet_infoline("Testing Dali::HitTestAlgorithm with a stencil");
368
369   Stage stage = Stage::GetCurrent();
370   Actor rootLayer = stage.GetRootLayer();
371   rootLayer.SetName( "RootLayer" );
372
373   // Create a layer
374   Layer layer = Layer::New();
375   layer.SetAnchorPoint( AnchorPoint::TOP_LEFT );
376   layer.SetParentOrigin( ParentOrigin::TOP_LEFT );
377   layer.SetName( "layer" );
378   stage.Add( layer );
379
380   // Create a stencil and add that to the layer
381   Actor stencil = ImageActor::New(Dali::BitmapImage::WHITE() );
382   stencil.SetAnchorPoint( AnchorPoint::TOP_LEFT );
383   stencil.SetParentOrigin( ParentOrigin::TOP_LEFT );
384   stencil.SetSize( 50.0f, 50.0f );
385   stencil.SetDrawMode( DrawMode::STENCIL );
386   stencil.SetName( "stencil" );
387   layer.Add( stencil );
388
389   // Create a renderable actor and add that to the layer
390   Actor layerHitActor = TextActor::New();
391   layerHitActor.SetSize( 100.0f, 100.0f );
392   layerHitActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
393   layerHitActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
394   layerHitActor.SetName( "layerHitActor" );
395   layer.Add( layerHitActor );
396
397   // Render and notify
398   application.SendNotification();
399   application.Render();
400
401   // Hit within stencil and actor
402   {
403     HitTestAlgorithm::Results results;
404     HitTest(stage, Vector2( 10.0f, 10.0f ), results, &DefaultIsActorTouchableFunction);
405     DALI_TEST_CHECK( results.actor == layerHitActor );
406     tet_printf( "Hit: %s\n", ( results.actor ? results.actor.GetName().c_str() : "NULL" ) );
407   }
408
409   // Hit within actor but outside of stencil, should hit the root-layer
410   {
411     HitTestAlgorithm::Results results;
412     HitTest(stage, Vector2( 60.0f, 60.0f ), results, &DefaultIsActorTouchableFunction);
413     DALI_TEST_CHECK( results.actor == rootLayer );
414     tet_printf( "Hit: %s\n", ( results.actor ? results.actor.GetName().c_str() : "NULL" ) );
415   }
416   END_TEST;
417 }