Fix SVG crash issue 36/293636/1
authorHeeyong Song <heeyong.song@samsung.com>
Thu, 1 Jun 2023 04:49:08 +0000 (13:49 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Thu, 1 Jun 2023 08:25:33 +0000 (17:25 +0900)
Remove previous task before create a new task

Change-Id: I77ef7d92e48d1ad256f9d2b07b6423e7b572ff5f

automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.h
automated-tests/src/dali-toolkit/utc-Dali-SvgVisual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/svg/svg-visual.cpp

index 8ce883dc1b3ec549affa3b1017ec5e4af3cb7ad0..85a143913541ec30b5f57c09f141ac1e18faefd6 100755 (executable)
@@ -80,6 +80,7 @@ SET(TC_SOURCES
   utc-Dali-ToggleButton.cpp
   utc-Dali-ScrollViewEffect.cpp
   utc-Dali-SuperBlurView.cpp
+  utc-Dali-SvgVisual.cpp
   utc-Dali-Toolkit.cpp
   utc-Dali-Model3dView.cpp
   utc-Dali-Visual.cpp
index 02f3d8f7d8d32016ef9dd09d1751b6a05587476b..c85110ab534ae38af40249e1c8d5695c3274a948 100644 (file)
 #include "toolkit-event-thread-callback.h"
 
 // EXTERNAL INCLUDES
-#include <cstddef>
-#include <semaphore.h>
 #include <math.h>
-#include <ctime>
+#include <semaphore.h>
+#include <unistd.h>
+#include <algorithm>
 #include <climits>
+#include <cstddef>
 #include <cstdio>
-#include <unistd.h>
+#include <ctime>
 #include <vector>
-#include <algorithm>
 
 namespace
 {
@@ -34,23 +34,21 @@ namespace
 // triggers from multiple threads - they should all be created on
 // event thread.
 std::vector<Dali::EventThreadCallback*> gEventThreadCallbacks;
-}
-
+} // namespace
 
 namespace Dali
 {
-
 struct EventThreadCallback::Impl
 {
   CallbackBase* callback;
-  sem_t mySemaphore;
+  sem_t         mySemaphore;
 };
 
-EventThreadCallback::EventThreadCallback( CallbackBase* callback )
-: mImpl( new Impl() )
+EventThreadCallback::EventThreadCallback(CallbackBase* callback)
+: mImpl(new Impl())
 {
   mImpl->callback = callback;
-  sem_init( &(mImpl->mySemaphore), 0, 0 );
+  sem_init(&(mImpl->mySemaphore), 0, 0);
 
   gEventThreadCallbacks.push_back(this);
 }
@@ -59,7 +57,7 @@ EventThreadCallback::~EventThreadCallback()
 {
   std::vector<EventThreadCallback*>::iterator iter =
     std::find(gEventThreadCallbacks.begin(), gEventThreadCallbacks.end(), this);
-  if( iter != gEventThreadCallbacks.end() )
+  if(iter != gEventThreadCallbacks.end())
   {
     gEventThreadCallbacks.erase(iter);
   }
@@ -68,15 +66,15 @@ EventThreadCallback::~EventThreadCallback()
 
 void EventThreadCallback::Trigger()
 {
-  sem_post( &(mImpl->mySemaphore) );
+  sem_post(&(mImpl->mySemaphore));
 }
 
 // returns true if timed out rather than triggered
 bool EventThreadCallback::WaitingForTrigger()
 {
   struct timespec now;
-  clock_gettime( CLOCK_REALTIME, &now );
-  if( now.tv_nsec < 999900000 ) // 999, 900, 000
+  clock_gettime(CLOCK_REALTIME, &now);
+  if(now.tv_nsec < 999900000) // 999, 900, 000
     now.tv_nsec += 1000;
   else
   {
@@ -84,7 +82,7 @@ bool EventThreadCallback::WaitingForTrigger()
     now.tv_nsec = 0;
   }
 
-  int error = sem_timedwait( &(mImpl->mySemaphore), &now );
+  int error = sem_timedwait(&(mImpl->mySemaphore), &now);
   return error != 0; // true if timeout
 }
 
@@ -93,57 +91,59 @@ CallbackBase* EventThreadCallback::GetCallback()
   return mImpl->callback;
 }
 
-}
-
+} // namespace Dali
 
 namespace Test
 {
-
-bool WaitForEventThreadTrigger( int triggerCount, int timeoutInSeconds )
+bool WaitForEventThreadTrigger(int triggerCount, int timeoutInSeconds, int executeCallbacks)
 {
   struct timespec startTime;
   struct timespec now;
-  clock_gettime( CLOCK_REALTIME, &startTime );
-  now.tv_sec = startTime.tv_sec;
+  clock_gettime(CLOCK_REALTIME, &startTime);
+  now.tv_sec  = startTime.tv_sec;
   now.tv_nsec = startTime.tv_nsec;
 
   // Round robin poll of each semaphore:
-  while ( triggerCount > 0 )
+  while(triggerCount > 0)
   {
-    if( gEventThreadCallbacks.size() > 0 )
+    if(gEventThreadCallbacks.size() > 0)
     {
-      for( std::vector<Dali::EventThreadCallback*>::iterator iter = gEventThreadCallbacks.begin();
-           iter != gEventThreadCallbacks.end(); ++iter )
+      for(std::vector<Dali::EventThreadCallback*>::iterator iter = gEventThreadCallbacks.begin();
+          iter != gEventThreadCallbacks.end();
+          ++iter)
       {
         Dali::EventThreadCallback* eventTrigger = (*iter);
-        Dali::CallbackBase* callback = eventTrigger->GetCallback();
-        bool timedout = eventTrigger->WaitingForTrigger();
-        if( ! timedout )
+        Dali::CallbackBase*        callback     = eventTrigger->GetCallback();
+        bool                       timedout     = eventTrigger->WaitingForTrigger();
+        if(!timedout)
         {
-          // Semaphore was unlocked - execute the trigger
-          Dali::CallbackBase::Execute( *callback );
+          if(executeCallbacks)
+          {
+            // Semaphore was unlocked - execute the trigger
+            Dali::CallbackBase::Execute(*callback);
+          }
           triggerCount--;
         }
-        if( triggerCount <= 0 )
+        if(triggerCount <= 0)
         {
           break;
         }
       }
     }
-    clock_gettime( CLOCK_REALTIME, &now );
-    if( now.tv_sec - startTime.tv_sec > timeoutInSeconds )
+    clock_gettime(CLOCK_REALTIME, &now);
+    if(now.tv_sec - startTime.tv_sec > timeoutInSeconds)
     {
       // Ensure we break out of the loop if elapsed time has passed
       break;
     }
   }
 
-  clock_gettime( CLOCK_REALTIME, &now );
-  if( now.tv_sec > startTime.tv_sec + 1 )
+  clock_gettime(CLOCK_REALTIME, &now);
+  if(now.tv_sec > startTime.tv_sec + 1)
   {
-    fprintf(stderr, "WaitForEventThreadTrigger took %ld seconds\n", now.tv_sec - startTime.tv_sec );
+    fprintf(stderr, "WaitForEventThreadTrigger took %ld seconds\n", now.tv_sec - startTime.tv_sec);
   }
   return triggerCount == 0;
 }
 
-}
+} // namespace Test
index 9693e6ef4e4f096831b1cc70873d149375bb87a9..6541b3e7b83f43af1b07ecba3ee84f30f58e58b2 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_EVENT_THREAD_CALLBACK_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 namespace Dali
 {
-
 class DALI_TOOLKIT_API EventThreadCallback
 {
 public:
-
-  EventThreadCallback( CallbackBase* callback );
+  EventThreadCallback(CallbackBase* callback);
 
   ~EventThreadCallback();
 
@@ -41,24 +39,21 @@ public:
   CallbackBase* GetCallback();
 
 private:
-
   // undefined copy constructor.
-  EventThreadCallback( const EventThreadCallback& );
+  EventThreadCallback(const EventThreadCallback&);
 
   // undefined assignment operator
-  EventThreadCallback& operator=( const EventThreadCallback& );
+  EventThreadCallback& operator=(const EventThreadCallback&);
 
 private:
-
   struct Impl;
   Impl* mImpl;
 };
 
-}
+} // namespace Dali
 
 namespace Test
 {
-
 /**
  * Wait for the tested code to create an event trigger, then
  * wait for triggerCount Trigger calls to occur, and execute the trigger
@@ -66,9 +61,8 @@ namespace Test
  *
  * Will wait for a maximum of 30s before failing the test and returning.
  */
-bool WaitForEventThreadTrigger( int triggerCount, int timeoutInSeconds=30 );
-
-}
+bool WaitForEventThreadTrigger(int triggerCount, int timeoutInSeconds = 30, int executeCallbacks = true);
 
+} // namespace Test
 
 #endif // DALI_TOOLKIT_EVENT_THREAD_CALLBACK_H
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-SvgVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-SvgVisual.cpp
new file mode 100644 (file)
index 0000000..48fd4ce
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dummy-control.h>
+#include <toolkit-event-thread-callback.h>
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_svg_visual_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_svg_visual_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+} // namespace
+
+int UtcDaliSvgVisualChageSize(void)
+{
+  tet_infoline("Test change transform");
+
+  ToolkitTestApplication application;
+
+  TraceCallStack& textureTrace = application.GetGlAbstraction().GetTextureTrace();
+  textureTrace.Enable(true);
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual(Property::Map().Add(ImageVisual::Property::URL, TEST_SVG_FILE_NAME));
+  DALI_TEST_CHECK(visual);
+
+  DummyControl      control   = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
+  dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+  application.SendNotification();
+
+  // Wait for loading
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  control.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
+  application.GetScene().Add(control);
+
+  visual.SetTransformAndSize(Property::Map(), Vector2(100, 100));
+
+  // Wait for rasterization but not execute the callback
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION);
+
+  // Change actor size before finishing rasterization
+  control.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
+  visual.SetTransformAndSize(Property::Map(), Vector2(300, 300));
+
+  application.SendNotification();
+
+  // Wait for rasterization
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  TraceCallStack::NamedParams params;
+  params["width"] << 300;
+  params["height"] << 300;
+  // Should be the final size
+  DALI_TEST_EQUALS(textureTrace.FindMethodAndParams("TexImage2D", params), true, TEST_LOCATION);
+
+  END_TEST;
+}
index 8fcbf52f86a95c8f6c57da68f78b702a99091847..2a1b09ffe4c8523ad506055fba12eb052f0d3431 100644 (file)
@@ -314,6 +314,13 @@ void SvgVisual::AddRasterizationTask(const Vector2& size)
 {
   if(mImpl->mRenderer)
   {
+    // Remove previous task
+    if(mRasterizingTask)
+    {
+      Dali::AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
+      mRasterizingTask.Reset();
+    }
+
     unsigned int width  = static_cast<unsigned int>(size.width);
     unsigned int height = static_cast<unsigned int>(size.height);