--- /dev/null
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ master, devel/vulkan ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ master ]
+ schedule:
+ - cron: '24 1 * * 1'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'cpp' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+ # Learn more:
+ # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v1
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ #- name: Autobuild
+ # uses: github/codeql-action/autobuild@v1
+
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ https://git.io/JvXDl
+
+ # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ - run: |
+ cd build/tizen
+ export DESKTOP_PREFIX=/tmp
+ cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX .
+ make -j8
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v1
utc-Dali-Internal-RotationGesture.cpp
utc-Dali-Internal-TapGesture.cpp
utc-Dali-Internal-TapGestureProcessor.cpp
+ utc-Dali-Internal-ConstString.cpp
)
LIST(APPEND TC_SOURCES
--- /dev/null
+/*
+ * Copyright (c) 2020 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-test-suite-utils.h>
+#include <dali/public-api/dali-core.h>
+
+#include <random>
+#include <string>
+
+// Internal headers are allowed here
+#include <dali/internal/common/const-string.h>
+
+using namespace Dali;
+
+namespace
+{
+std::string RandomString(size_t length)
+{
+ static auto& chrs =
+ "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ thread_local static std::mt19937 rg{std::random_device{}()};
+ thread_local static std::uniform_int_distribution<std::string::size_type> pick(0, sizeof(chrs) - 2);
+
+ std::string s;
+
+ s.reserve(length);
+
+ while(length--)
+ s += chrs[pick(rg)];
+
+ return s;
+}
+} // namespace
+
+void utc_dali_internal_conststring_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_internal_conststring_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+int UtcDaliConstStringEmpty(void)
+{
+ Internal::ConstString str1;
+ DALI_TEST_EQUALS(str1.IsEmpty(), true, TEST_LOCATION);
+
+ Internal::ConstString str2("hello");
+ DALI_TEST_EQUALS(str2.IsEmpty(), false, TEST_LOCATION);
+
+ str2.Clear();
+ DALI_TEST_EQUALS(str2.IsEmpty(), true, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliConstStringConstruct(void)
+{
+ Internal::ConstString str1("string1");
+ DALI_TEST_EQUALS(str1.GetCString(), "string1", TEST_LOCATION);
+
+ Internal::ConstString str2("string1");
+
+ DALI_TEST_EQUALS(str2.GetCString(), "string1", TEST_LOCATION);
+
+ bool samePointer = (str1.GetCString() == str2.GetCString());
+ DALI_TEST_EQUALS(samePointer, true, TEST_LOCATION);
+
+ str1.Clear();
+ DALI_TEST_EQUALS(str2.GetCString(), "string1", TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliConstStringConstructStringView(void)
+{
+ Internal::ConstString str1(std::string_view("random string"));
+
+ DALI_TEST_EQUALS(str1.GetStringView().data(), "random string", TEST_LOCATION);
+ DALI_TEST_EQUALS(str1.GetStringView().size(), 13, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliConstStringSetString(void)
+{
+ Internal::ConstString str1(std::string_view("current string"));
+
+ DALI_TEST_EQUALS(str1.GetStringView().data(), "current string", TEST_LOCATION);
+
+ str1.SetString("new string");
+
+ DALI_TEST_EQUALS(str1.GetCString(), "new string", TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliConstStringStressTest(void)
+{
+ static constexpr size_t DB_SIZE = 2000;
+
+ std::vector<std::string> Database;
+ Database.reserve(DB_SIZE);
+
+ std::vector<Internal::ConstString> constStringDB;
+ constStringDB.reserve(DB_SIZE);
+
+ std::vector<Internal::ConstString> constStringDB1;
+ constStringDB1.reserve(DB_SIZE);
+
+ for(auto i = 0u; i < DB_SIZE; i++)
+ {
+ if(i % 3 == 0)
+ {
+ Database.push_back(RandomString(10));
+ }
+ else if(i % 4 == 0)
+ {
+ Database.push_back(RandomString(7));
+ }
+ else
+ {
+ Database.push_back(RandomString(11));
+ }
+ constStringDB.push_back(Internal::ConstString(Database[i]));
+ constStringDB1.push_back(Internal::ConstString(Database[i]));
+ }
+
+ // check eqality betwwen original string and constString
+ for(auto i = 0u; i < DB_SIZE; i++)
+ {
+ DALI_TEST_EQUALS(constStringDB[i].GetCString(), Database[i].c_str(), TEST_LOCATION);
+ }
+
+ // check pointer eqality betwwen 2 constString
+ for(auto i = 0u; i < DB_SIZE; i++)
+ {
+ bool pointerEqual = (constStringDB[i] == constStringDB1[i]);
+ DALI_TEST_EQUALS(pointerEqual, true, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
void DALI_TEST_EQUALS(const char* str1, const std::string& str2, const char* location);
/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<const std::string_view>(std::string_view str1, std::string_view str2, const char* location)
+{
+ DALI_TEST_EQUALS(str1.data(), str2.data(), location);
+}
+
+inline void DALI_TEST_EQUALS(std::string_view str1, const char* str2, const char* location)
+{
+ DALI_TEST_EQUALS(str1.data(), str2, location);
+}
+
+inline void DALI_TEST_EQUALS(std::string_view str1, const std::string& str2, const char* location)
+{
+ DALI_TEST_EQUALS(str1.data(), str2.c_str(), location);
+}
+
+inline void DALI_TEST_EQUALS(const std::string& str2, std::string_view str1, const char* location)
+{
+ DALI_TEST_EQUALS(str2.c_str(), str1.data(), location);
+}
+
+inline void DALI_TEST_EQUALS(const char* str1, std::string_view str2, const char* location)
+{
+ DALI_TEST_EQUALS(str1, str2.data(), location);
+}
+
+/**
* Test if a property value type is equal to a trivial type.
*/
template<typename Type>
END_TEST;
}
+int UtcDaliActorRaiseAbove2(void)
+{
+ tet_infoline("UtcDaliActor RaiseToAbove test using SIBLING_ORDER property\n");
+
+ TestApplication application;
+
+ Integration::Scene stage(application.GetScene());
+
+ Actor actorA = Actor::New();
+ Actor actorB = Actor::New();
+ Actor actorC = Actor::New();
+
+ actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+ actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+ actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+ actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+ actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+ actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+ stage.Add(actorA);
+ stage.Add(actorB);
+ stage.Add(actorC);
+
+ ResetTouchCallbacks();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+ // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+ // Only top actor will get touched.
+ actorA.TouchedSignal().Connect(TestTouchCallback);
+ actorB.TouchedSignal().Connect(TestTouchCallback2);
+ actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+ bool orderChangedSignal(false);
+ Actor orderChangedActor;
+ ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+ DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+ Dali::Integration::Point point;
+ point.SetDeviceId(1);
+ point.SetState(PointState::DOWN);
+ point.SetScreenPosition(Vector2(10.f, 10.f));
+ Dali::Integration::TouchEvent touchEvent;
+ touchEvent.AddPoint(point);
+
+ application.ProcessEvent(touchEvent);
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+ ResetTouchCallbacks();
+
+ tet_printf("Raise actor B Above Actor C\n");
+
+ DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+ int newOrder = actorC[DevelActor::Property::SIBLING_ORDER];
+ actorB[DevelActor::Property::SIBLING_ORDER] = newOrder;
+ DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+ // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+ application.SendNotification();
+ application.ProcessEvent(touchEvent);
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+ ResetTouchCallbacks();
+
+ tet_printf("Raise actor A Above Actor B\n");
+
+ orderChangedSignal = false;
+
+ DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+ newOrder = actorB[DevelActor::Property::SIBLING_ORDER];
+ actorA[DevelActor::Property::SIBLING_ORDER] = newOrder;
+ DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
+
+ // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+ application.SendNotification();
+
+ application.ProcessEvent(touchEvent); // process a touch event on ordered actors.
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+ ResetTouchCallbacks();
+
+ END_TEST;
+}
+
int UtcDaliActorLowerBelow(void)
{
tet_infoline("UtcDaliActor LowerBelow test \n");
END_TEST;
}
+
+int UtcDaliActorLowerBelow2(void)
+{
+ tet_infoline("UtcDaliActor LowerBelow test using SIBLING_ORDER property\n");
+
+ TestApplication application;
+
+ Integration::Scene stage(application.GetScene());
+
+ // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
+ // enables checking of which actor the uniform is assigned too
+ Shader shaderA = CreateShader();
+ shaderA.RegisterProperty("uRendererColor", 1.f);
+
+ Shader shaderB = CreateShader();
+ shaderB.RegisterProperty("uRendererColor", 2.f);
+
+ Shader shaderC = CreateShader();
+ shaderC.RegisterProperty("uRendererColor", 3.f);
+
+ Actor actorA = Actor::New();
+ Actor actorB = Actor::New();
+ Actor actorC = Actor::New();
+
+ // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
+ Geometry geometry = CreateQuadGeometry();
+
+ Renderer rendererA = Renderer::New(geometry, shaderA);
+ actorA.AddRenderer(rendererA);
+
+ Renderer rendererB = Renderer::New(geometry, shaderB);
+ actorB.AddRenderer(rendererB);
+
+ Renderer rendererC = Renderer::New(geometry, shaderC);
+ actorC.AddRenderer(rendererC);
+
+ actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+ actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+ actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+ actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+ actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+ actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+ Actor container = Actor::New();
+ container.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ container.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+ stage.Add(container);
+
+ container.Add(actorA);
+ container.Add(actorB);
+ container.Add(actorC);
+
+ ResetTouchCallbacks();
+
+ // Connect ChildOrderChangedSignal
+ bool orderChangedSignal(false);
+ Actor orderChangedActor;
+ ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+ DevelActor::ChildOrderChangedSignal(container).Connect(&application, f);
+
+ // Set up gl abstraction trace so can query the set uniform order
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ glAbstraction.EnableSetUniformCallTrace(true);
+ glAbstraction.ResetSetUniformCallStack();
+ TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+ glAbstraction.ResetSetUniformCallStack();
+
+ application.SendNotification();
+ application.Render();
+
+ glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+ tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+ // Test order of uniforms in stack
+ int indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3");
+ int indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2");
+ int indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1");
+
+ tet_infoline("Testing C above B and A at bottom\n");
+ bool CBA = (indexC > indexB) && (indexB > indexA);
+
+ DALI_TEST_EQUALS(CBA, true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+ // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+ // Only top actor will get touched.
+ actorA.TouchedSignal().Connect(TestTouchCallback);
+ actorB.TouchedSignal().Connect(TestTouchCallback2);
+ actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+ Dali::Integration::Point point;
+ point.SetDeviceId(1);
+ point.SetState(PointState::DOWN);
+ point.SetScreenPosition(Vector2(10.f, 10.f));
+ Dali::Integration::TouchEvent touchEvent;
+ touchEvent.AddPoint(point);
+
+ tet_infoline("UtcDaliActor Test Set up completed \n");
+
+ application.ProcessEvent(touchEvent);
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+ ResetTouchCallbacks();
+
+ tet_printf("Lower actor C below Actor B ( actor B and A on same level due to insertion order) so C is below both \n");
+
+ DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+ actorC[DevelActor::Property::SIBLING_ORDER] = 1;
+ DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+ // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+ application.SendNotification();
+ application.Render();
+
+ application.ProcessEvent(touchEvent); // touch event
+
+ glAbstraction.ResetSetUniformCallStack();
+ glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+ application.SendNotification();
+ application.Render();
+
+ tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+ // Test order of uniforms in stack
+ indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3");
+ indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2");
+ indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1");
+
+ tet_infoline("Testing render order is A, C, B");
+ DALI_TEST_EQUALS(indexC > indexA, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(indexB > indexC, true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+ ResetTouchCallbacks();
+
+ tet_printf("Lower actor C below Actor A leaving B on top\n");
+
+ orderChangedSignal = false;
+
+ DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+ actorC[DevelActor::Property::SIBLING_ORDER] = 0;
+ DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+ // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+ application.SendNotification();
+ application.Render();
+
+ application.ProcessEvent(touchEvent);
+
+ glAbstraction.ResetSetUniformCallStack();
+ glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+ application.Render();
+ tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+ // Test order of uniforms in stack
+ indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3");
+ indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2");
+ indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1");
+
+ DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(indexB > indexA, true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+ ResetTouchCallbacks();
+
+ tet_printf("Lower actor B below Actor C leaving A on top\n");
+
+ orderChangedSignal = false;
+
+ DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+ actorB[DevelActor::Property::SIBLING_ORDER] = 0;
+ DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+ // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+ application.SendNotification();
+ application.Render();
+
+ application.ProcessEvent(touchEvent);
+
+ glAbstraction.ResetSetUniformCallStack();
+ glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+ application.Render();
+ tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+ // Test order of uniforms in stack
+ indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3");
+ indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2");
+ indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1");
+
+ DALI_TEST_EQUALS(indexC > indexB, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliActorRaiseAboveDifferentParentsN(void)
{
tet_infoline("UtcDaliActor RaiseToAbove test with actor and target actor having different parents \n");
END_TEST;
}
+int UtcDaliRendererSetBlendMode08(void)
+{
+ TestApplication application;
+
+ tet_infoline("Test setting the blend mode to auto with opaque color and Advanced Blend Equation.");
+
+ if( Dali::Capabilities::IsBlendEquationSupported( DevelBlendEquation::SCREEN ) )
+ {
+ Geometry geometry = CreateQuadGeometry();
+ Shader shader = CreateShader();
+ Renderer renderer = Renderer::New(geometry, shader);
+
+ Actor actor = Actor::New();
+ actor.SetProperty(Actor::Property::OPACITY, 1.0f);
+ actor.AddRenderer(renderer);
+ actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+ application.GetScene().Add(actor);
+
+ renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::AUTO);
+ renderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true );
+ renderer.SetProperty( DevelRenderer::Property::BLEND_EQUATION, DevelBlendEquation::SCREEN );
+
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ glAbstraction.EnableEnableDisableCallTrace(true);
+
+ application.SendNotification();
+ application.Render();
+
+ TraceCallStack& glEnableStack = glAbstraction.GetEnableDisableTrace();
+ std::ostringstream blendStr;
+ blendStr << GL_BLEND;
+ DALI_TEST_CHECK(glEnableStack.FindMethodAndParams("Enable", blendStr.str().c_str()));
+ }
+
+ END_TEST;
+}
+
+int UtcDaliRendererSetBlendMode08b(void)
+{
+ TestApplication application;
+
+ tet_infoline("Test setting the blend mode to off with opaque color and Advanced Blend Equation.");
+
+ if( Dali::Capabilities::IsBlendEquationSupported( DevelBlendEquation::SCREEN ) )
+ {
+ Geometry geometry = CreateQuadGeometry();
+ Shader shader = CreateShader();
+ Renderer renderer = Renderer::New(geometry, shader);
+
+ Actor actor = Actor::New();
+ actor.SetProperty(Actor::Property::OPACITY, 1.0f);
+ actor.AddRenderer(renderer);
+ actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+ application.GetScene().Add(actor);
+
+ renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::OFF);
+ renderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true );
+ renderer.SetProperty( DevelRenderer::Property::BLEND_EQUATION, DevelBlendEquation::SCREEN );
+
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ glAbstraction.EnableEnableDisableCallTrace(true);
+
+ application.SendNotification();
+ application.Render();
+
+ TraceCallStack& glEnableStack = glAbstraction.GetEnableDisableTrace();
+ std::ostringstream blendStr;
+ blendStr << GL_BLEND;
+ DALI_TEST_CHECK(!glEnableStack.FindMethodAndParams("Enable", blendStr.str().c_str()));
+ }
+
+ END_TEST;
+}
+
int UtcDaliRendererGetBlendMode(void)
{
TestApplication application;
#include <dali/integration-api/events/hover-event-integ.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/internal/event/common/type-info-impl.h>
+#include <dali/internal/common/const-string.h>
#include <dali/public-api/dali-core.h>
#include <stdlib.h>
// check the child property type
Internal::TypeInfo& typeInfoImpl = GetImplementation(typeInfo);
- Property::Type type = typeInfoImpl.GetChildPropertyType(typeInfoImpl.GetChildPropertyIndex("childProp4"));
+ Property::Type type = typeInfoImpl.GetChildPropertyType(typeInfoImpl.GetChildPropertyIndex(Dali::Internal::ConstString("childProp4")));
DALI_TEST_EQUALS(type, Property::INTEGER, TEST_LOCATION);
std::string unRegisteredChildName(typeInfoImpl.GetChildPropertyName(CHILD_PROPERTY_REGISTRATION_START_INDEX + 4));
( ( indexA >= BLENDING_EQUATION_ADVANCED_INDEX_START ) && ( indexA <= BLENDING_EQUATION_ADVANCED_INDEX_END ) ) );
}
+bool BlendingOptions::IsAdvancedBlendEquationIncluded( unsigned int bitmask )
+{
+ unsigned int indexRgb = bitmask & MASK_EQUATION_RGB;
+ indexRgb = indexRgb >> SHIFT_TO_EQUATION_RGB;
+ unsigned int indexA = bitmask & MASK_EQUATION_ALPHA;
+ indexA = indexA >> SHIFT_TO_EQUATION_ALPHA;
+
+ return ( ( ( indexRgb >= BLENDING_EQUATION_ADVANCED_INDEX_START ) && ( indexRgb <= BLENDING_EQUATION_ADVANCED_INDEX_END ) ) ||
+ ( ( indexA >= BLENDING_EQUATION_ADVANCED_INDEX_START ) && ( indexA <= BLENDING_EQUATION_ADVANCED_INDEX_END ) ) );
+}
+
bool BlendingOptions::IsAdvancedBlendEquation( DevelBlendEquation::Type equation )
{
switch ( equation )
bool IsAdvancedBlendEquationApplied();
/**
+ * Query whether input bit mask include advanced blend equation.
+ * @return True if the bit mask include advanced blend equation.
+ */
+ static bool IsAdvancedBlendEquationIncluded( unsigned int bitmask );
+
+ /**
* Query whether input blend equation is advanced option.
* @return True if input blend equation is advanced.
*/
--- /dev/null
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/common/const-string.h>
+
+// EXTERNAL INCLUDES
+#include <cstddef>
+#include <cstring>
+#include <functional>
+#include <vector>
+#include <mutex>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+// local namespace
+namespace
+{
+class ArenaAllocator
+{
+
+public:
+ ArenaAllocator()
+ {
+ mPages.reserve(10);
+ EnsureSpace();
+ }
+ ~ArenaAllocator()
+ {
+ for(auto& page : mPages)
+ {
+ delete[] page;
+ }
+ }
+ char* Allocate(uint32_t size, uint32_t alignment)
+ {
+ uintptr_t mask = alignment - 1;
+ uintptr_t alignedOffset = (~reinterpret_cast<uintptr_t>(mCursor) + 1) & mask;
+ uintptr_t totalSize = size + alignedOffset;
+
+ if(totalSize > static_cast<uintptr_t>(mEnd - mCursor))
+ {
+ EnsureSpace();
+ alignedOffset = (~reinterpret_cast<uintptr_t>(mCursor) + 1) & mask;
+ }
+ char* ptr = mCursor + alignedOffset;
+ mCursor = ptr + size;
+ return ptr;
+ }
+
+private:
+ void EnsureSpace()
+ {
+ constexpr size_t pageSize = 4096;
+ char* page = new char[pageSize];
+ mPages.push_back(page);
+ mCursor = page;
+ mEnd = mCursor + pageSize;
+ }
+
+ char* mCursor{nullptr};
+ char* mEnd{nullptr};
+ std::vector<char*> mPages;
+};
+
+class StringEntry
+{
+public:
+ explicit StringEntry(uint16_t stringLength)
+ : mStringLength(stringLength)
+ {
+ }
+ size_t getStringLength() const
+ {
+ return mStringLength;
+ }
+ const char* GetStringData() const
+ {
+ return reinterpret_cast<const char*>(this + 1);
+ }
+
+ std::string_view GetString() const
+ {
+ return std::string_view(GetStringData(), getStringLength());
+ }
+ /**
+ * GetStringEntryFromData - Given key data that is known to be embedded
+ * into a StringEntry, return the StringEntry itself.
+ */
+ static StringEntry& GetStringEntryFromData(const char* stringData)
+ {
+ char* ptr = const_cast<char*>(stringData) - sizeof(StringEntry);
+ return *reinterpret_cast<StringEntry*>(ptr);
+ }
+ /**
+ * Create a StringEntry from string_view
+ *
+ */
+ static StringEntry* Create(std::string_view str, ArenaAllocator& allocator)
+ {
+ size_t length = str.size();
+
+ // Allocate a new item with space for the string at the end and a null
+ // terminator.
+ size_t allocSize = sizeof(StringEntry) + length + 1;
+ size_t alignment = alignof(StringEntry);
+
+ // Construct the value.
+ StringEntry* newItem = new(allocator.Allocate(allocSize, alignment)) StringEntry(length);
+
+ // Copy the string information.
+ char* strBuffer = const_cast<char*>(newItem->GetStringData());
+ if(length > 0)
+ memcpy(strBuffer, str.data(), length);
+ strBuffer[length] = 0; // Null terminate.
+ return newItem;
+ }
+
+private:
+ uint16_t mStringLength;
+};
+
+class StringPool
+{
+public:
+ unsigned Size() const
+ {
+ return mItems;
+ }
+ StringPool()
+ {
+ Init();
+ }
+
+ static StringPool& Instance()
+ {
+ static StringPool object;
+ return object;
+ }
+
+ const char* Intern(std::string_view str)
+ {
+ const std::lock_guard<std::mutex> lock(mMutex);
+
+ auto bucketNumber = FindBucket(str);
+ auto& bucket = mTable[bucketNumber];
+
+ if(bucket)
+ {
+ // string already exists
+ return bucket->GetStringData();
+ }
+
+ // assign the newly created StringEntry to the designated bucket.
+ bucket = StringEntry::Create(str, mAllocator);
+
+ ++mItems;
+
+ bucketNumber = RehashTable(bucketNumber);
+
+ return mTable[bucketNumber]->GetStringData();
+ }
+
+private:
+ unsigned NextBucket(unsigned currentBucket, unsigned totalBucket, unsigned ProbeAmount)
+ {
+ return (currentBucket + ProbeAmount) & (totalBucket - 1);
+ }
+
+ void Init()
+ {
+ unsigned newBuckets = 512;
+ /**
+ * for memory efficiency and cache locality we store the StringEntry and corresponding HashValue in separate
+ * segments in this way each entry in the bucket will take 12byte instead of 16 if we keep them together.
+ * So we allocate one memory and treat 1st segment as a array of StringEntry* and the second segment as array of
+ * unsigned*.
+ */
+ mTable = static_cast<StringEntry**>(calloc(newBuckets + 1, sizeof(StringEntry**) + sizeof(unsigned)));
+ DALI_ASSERT_ALWAYS(mTable && "calloc returned nullptr");
+
+ mBuckets = newBuckets;
+ }
+
+ unsigned FindBucket(std::string_view name)
+ {
+ unsigned bucketSize = mBuckets;
+ unsigned fullHashValue = std::hash<std::string_view>{}(name);
+ unsigned bucketNumber = fullHashValue & (bucketSize - 1);
+ // point to the start of the hashvalue segment.
+ unsigned* hashTable = reinterpret_cast<unsigned*>(mTable + mBuckets + 1);
+
+ unsigned probeAmt = 1;
+ while(true)
+ {
+ StringEntry* bucketItem = mTable[bucketNumber];
+ // If we found an empty bucket, this key isn't in the table yet, return it.
+ if(!bucketItem)
+ {
+ hashTable[bucketNumber] = fullHashValue;
+ return bucketNumber;
+ }
+
+ if(hashTable[bucketNumber] == fullHashValue)
+ {
+ // If the full hash value matches, check deeply for a match.
+ if(name == bucketItem->GetString())
+ {
+ // We found a match!
+ return bucketNumber;
+ }
+ }
+
+ // Okay, we didn't find the item. Probe to the next bucket.
+ bucketNumber = NextBucket(bucketNumber, bucketSize, probeAmt);
+
+ // Use quadratic probing, it has fewer clumping artifacts than linear
+ ++probeAmt;
+ }
+ }
+ unsigned RehashTable(unsigned bucketNumber)
+ {
+ unsigned newSize;
+ unsigned* hashTable = reinterpret_cast<unsigned*>(mTable + mBuckets + 1);
+
+ // If the hash table is now more than 3/4 full.
+ // grow/rehash the table.
+ if((mItems * 4) > (mBuckets * 3))
+ {
+ newSize = mBuckets * 2;
+ }
+ else
+ {
+ return bucketNumber;
+ }
+ unsigned newBucketNumber = bucketNumber;
+
+ // Allocate one extra bucket which will always be non-empty.
+ auto newTable = static_cast<StringEntry**>(calloc(newSize + 1, sizeof(StringEntry*) + sizeof(unsigned)));
+ DALI_ASSERT_ALWAYS(newTable && "calloc returned nullptr");
+
+ // point to the start of the hashvalue segment. as the pointer is of type StringEntry* , but the
+ // second segment keeps only unsigned data hence the reinterpret_cast.
+ unsigned* newHashTable = reinterpret_cast<unsigned*>(newTable + newSize + 1);
+
+ // Rehash all the items into their new buckets.
+ for(unsigned i = 0, j = mBuckets; i != j; ++i)
+ {
+ StringEntry* bucket = mTable[i];
+ if(bucket)
+ {
+ // Fast case, bucket available.
+ unsigned fullHash = hashTable[i];
+ unsigned newBucket = fullHash & (newSize - 1);
+ if(!newTable[newBucket])
+ {
+ newTable[fullHash & (newSize - 1)] = bucket;
+ newHashTable[fullHash & (newSize - 1)] = fullHash;
+ if(i == bucketNumber)
+ newBucketNumber = newBucket;
+ continue;
+ }
+
+ // Otherwise probe for a spot.
+ unsigned ProbeSize = 1;
+ do
+ {
+ newBucket = NextBucket(newBucket, newSize, ProbeSize++);
+ } while(newTable[newBucket]);
+
+ // Finally found a slot. Fill it in.
+ newTable[newBucket] = bucket;
+ newHashTable[newBucket] = fullHash;
+ if(i == bucketNumber)
+ newBucketNumber = newBucket;
+ }
+ }
+
+ free(mTable);
+
+ mTable = newTable;
+ mBuckets = newSize;
+ return newBucketNumber;
+ }
+
+private:
+ std::mutex mMutex;
+ ArenaAllocator mAllocator;
+ StringEntry** mTable{nullptr};
+ unsigned mBuckets{0};
+ unsigned mItems{0};
+};
+
+} // namespace
+
+Dali::Internal::ConstString::ConstString(std::string_view str)
+{
+ mString = StringPool::Instance().Intern(str);
+}
+
+size_t Dali::Internal::ConstString::GetLength() const
+{
+ return mString ? StringEntry::GetStringEntryFromData(mString).getStringLength() : 0;
+}
+
+void Dali::Internal::ConstString::SetString(std::string_view str)
+{
+ if(str.empty())
+ {
+ mString = nullptr;
+ }
+ else
+ {
+ mString = StringPool::Instance().Intern(str);
+ }
+}
--- /dev/null
+#ifndef DALI_INTERNAL_CONST_STRING_H
+#define DALI_INTERNAL_CONST_STRING_H
+
+/*
+ * Copyright (c) 2020 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 <string_view>
+
+namespace Dali
+{
+namespace Internal
+{
+/**
+ * A uniqued constant string class.
+ *
+ * Provides an efficient way to store strings as uniqued strings. After the
+ * strings are uniqued, finding strings that are equal to one another is very
+ * fast as just the pointers need to be compared. It also allows for many
+ * common strings from many different sources to be shared to keep the memory
+ * footprint low.
+ *
+ * No reference counting is done on strings that are added to the string
+ * pool, once strings are added they are in the string pool for the life of
+ * the program.
+ */
+class ConstString
+{
+public:
+ /**
+ * Default constructor
+ *
+ * Initializes the string to an empty string.
+ */
+ ConstString() = default;
+
+ explicit ConstString(std::string_view str);
+
+ /**
+ * Convert to bool operator.
+ *
+ * This allows code to check a ConstString object to see if it contains a
+ * valid string using code such as:
+ *
+ * \code
+ * ConstString str(...);
+ * if (str)
+ * { ...
+ * \endcode
+ *
+ * \return
+ * /b True this object contains a valid non-empty C string, \b
+ * false otherwise.
+ */
+ explicit operator bool() const
+ {
+ return !IsEmpty();
+ }
+
+ /**
+ * Equal to operator
+ *
+ * Returns true if this string is equal to the string in \a rhs. This
+ * operation is very fast as it results in a pointer comparison since all
+ * strings are in a uniqued in a global string pool.
+ *
+ * \param[in] rhs
+ * Another string object to compare this object to.
+ *
+ * \return
+ * true if this object is equal to \a rhs.
+ * false if this object is not equal to \a rhs.
+ */
+ bool operator==(ConstString rhs) const
+ {
+ // We can do a pointer compare to compare these strings since they must
+ // come from the same pool in order to be equal.
+ return mString == rhs.mString;
+ }
+
+ /**
+ * Equal to operator against a non-ConstString value.
+ *
+ * Returns true if this string is equal to the string in \a rhs.
+ *
+ * \param[in] rhs
+ * Another string object to compare this object to.
+ *
+ * \return
+ * \b true if this object is equal to \a rhs.
+ * \b false if this object is not equal to \a rhs.
+ */
+ bool operator==(const char* rhs) const
+ {
+ // ConstString differentiates between empty strings and nullptr strings, but
+ // StringRef doesn't. Therefore we have to do this check manually now.
+ if(mString == nullptr && rhs != nullptr)
+ return false;
+ if(mString != nullptr && rhs == nullptr)
+ return false;
+
+ return GetStringView() == rhs;
+ }
+
+ /**
+ * Not equal to operator
+ *
+ * Returns true if this string is not equal to the string in \a rhs. This
+ * operation is very fast as it results in a pointer comparison since all
+ * strings are in a uniqued in a global string pool.
+ *
+ * \param[in] rhs
+ * Another string object to compare this object to.
+ *
+ * \return
+ * \b true if this object is not equal to \a rhs.
+ * \b false if this object is equal to \a rhs.
+ */
+ bool operator!=(ConstString rhs) const
+ {
+ return mString != rhs.mString;
+ }
+
+ /**
+ * Not equal to operator against a non-ConstString value.
+ *
+ * Returns true if this string is not equal to the string in \a rhs.
+ *
+ * \param[in] rhs
+ * Another string object to compare this object to.
+ *
+ * \return \b true if this object is not equal to \a rhs, false otherwise.
+ */
+ bool operator!=(const char* rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ /**
+ * Get the string value as a std::string_view
+ *
+ * \return
+ * Returns a new std::string_view object filled in with the
+ * needed data.
+ */
+ std::string_view GetStringView() const
+ {
+ return mString ? std::string_view(mString, GetLength()) : std::string_view();
+ }
+
+ /**
+ * Get the string value as a C string.
+ *
+ * Get the value of the contained string as a NULL terminated C string
+ * value. This function will always return nullptr if the string is not valid.
+ * So this function is a direct accessor to the string pointer value.
+ *
+ * \return
+ * Returns nullptr the string is invalid, otherwise the C string
+ * value contained in this object.
+ */
+ const char* GetCString() const
+ {
+ return mString;
+ }
+
+ /**
+ * Get the length in bytes of string value.
+ *
+ * The string pool stores the length of the string, so we can avoid calling
+ * strlen() on the pointer value with this function.
+ *
+ * \return
+ * Returns the number of bytes that this string occupies in
+ * memory, not including the NULL termination byte.
+ */
+ size_t GetLength() const;
+
+ /**
+ * Clear this object's state.
+ *
+ * Clear any contained string and reset the value to the empty string
+ * value.
+ */
+ void Clear()
+ {
+ mString = nullptr;
+ }
+
+ /**
+ * Test for empty string.
+ *
+ * \return
+ * \b true if the contained string is empty.
+ * \b false if the contained string is not empty.
+ */
+ bool IsEmpty() const
+ {
+ return mString == nullptr || mString[0] == '\0';
+ }
+
+ /**
+ * Set the string_view value.
+ *
+ * Set the string value in the object by uniquing the \a str string value
+ * in our global string pool.
+ *
+ * If the string is already exists in the global string pool, it finds the
+ * current entry and returns the existing value. If it doesn't exist, it is
+ * added to the string pool.
+ *
+ * \param[in] str
+ * A string_view to add to the string pool.
+ */
+ void SetString(std::string_view str);
+
+private:
+ const char* mString{nullptr};
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_CONST_STRING_H
using CustomActorPtr = IntrusivePtr<CustomActor>;
using LayerPtr = IntrusivePtr<Layer>;
+using ActorContainer = std::vector<ActorPtr>;
+using ActorIter = ActorContainer::iterator;
+using ActorConstIter = ActorContainer::const_iterator;
+
} // namespace Internal
} // namespace Dali
#include <dali/public-api/object/type-registry.h>
#include <dali/devel-api/common/capabilities.h>
#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/internal/event/events/actor-gesture-data.h>
#include <dali/internal/event/actors/actor-property-handler.h>
#include <dali/internal/event/actors/actor-relayouter.h>
-#include <dali/internal/event/common/event-thread-services.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/actors/actor-siblings.h>
#include <dali/internal/event/actors/camera-actor-impl.h>
-#include <dali/internal/event/render-tasks/render-task-list-impl.h>
+#include <dali/internal/event/common/event-thread-services.h>
+#include <dali/internal/event/common/projection.h>
#include <dali/internal/event/common/property-helper.h>
-#include <dali/internal/event/common/stage-impl.h>
-#include <dali/internal/event/common/type-info-impl.h>
#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/common/stage-impl.h>
#include <dali/internal/event/common/thread-local-storage.h>
-#include <dali/internal/event/common/projection.h>
+#include <dali/internal/event/common/type-info-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/render-tasks/render-task-list-impl.h>
#include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
#include <dali/internal/update/nodes/node-messages.h>
-#include <dali/internal/event/events/actor-gesture-data.h>
#include <dali/integration-api/debug.h>
using Dali::Internal::SceneGraph::Node;
#if defined(DEBUG_ENABLED)
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_DEPTH_TIMER" );
-Debug::Filter* gLogRelayoutFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_TIMER" );
#endif
namespace Dali
if(mIsBlendEquationSet)
{
- renderer.SetBlendMode(Dali::BlendMode::ON);
renderer.SetBlendEquation(static_cast<DevelBlendEquation::Type>(mBlendEquation));
}
for(uint32_t i = 0; i < rendererCount; ++i)
{
RendererPtr renderer = GetRendererAt(i);
- renderer->SetBlendMode(Dali::BlendMode::ON);
renderer->SetBlendEquation(static_cast<DevelBlendEquation::Type>(blendEquation));
}
}
return 0.0f; // Default
}
-void Actor::NegotiateDimension( Dimension::Type dimension, const Vector2& allocatedSize, ActorDimensionStack& recursionStack )
-{
- // Check if it needs to be negotiated
- if( IsLayoutDirty( dimension ) && !IsLayoutNegotiated( dimension ) )
- {
- // Check that we havn't gotten into an infinite loop
- ActorDimensionPair searchActor = ActorDimensionPair( this, dimension );
- bool recursionFound = false;
- for( auto& element : recursionStack )
- {
- if( element == searchActor )
- {
- recursionFound = true;
- break;
- }
- }
-
- if( !recursionFound )
- {
- // Record the path that we have taken
- recursionStack.push_back( ActorDimensionPair( this, dimension ) );
-
- // Dimension dependency check
- for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
- {
- Dimension::Type dimensionToCheck = static_cast< Dimension::Type >( 1 << i );
-
- if( RelayoutDependentOnDimension( dimension, dimensionToCheck ) )
- {
- NegotiateDimension( dimensionToCheck, allocatedSize, recursionStack );
- }
- }
-
- // Parent dependency check
- Actor* parent = GetParent();
- if( parent && RelayoutDependentOnParent( dimension ) )
- {
- parent->NegotiateDimension( dimension, allocatedSize, recursionStack );
- }
-
- // Children dependency check
- if( RelayoutDependentOnChildren( dimension ) )
- {
- for( uint32_t i = 0, count = GetChildCount(); i < count; ++i )
- {
- ActorPtr child = GetChildAt( i );
-
- // Only relayout child first if it is not dependent on this actor
- if( !child->RelayoutDependentOnParent( dimension ) )
- {
- child->NegotiateDimension( dimension, allocatedSize, recursionStack );
- }
- }
- }
-
- // For deriving classes
- OnCalculateRelayoutSize( dimension );
-
- // All dependencies checked, calculate the size and set negotiated flag
- const float newSize = Relayouter::ClampDimension( *this, CalculateSize( dimension, allocatedSize ), dimension );
-
- SetNegotiatedDimension( newSize, dimension );
- SetLayoutNegotiated( true, dimension );
-
- // For deriving classes
- OnLayoutNegotiated( newSize, dimension );
-
- // This actor has been successfully processed, pop it off the recursion stack
- recursionStack.pop_back();
- }
- else
- {
- // TODO: Break infinite loop
- SetLayoutNegotiated( true, dimension );
- }
- }
-}
-
-void Actor::NegotiateDimensions( const Vector2& allocatedSize )
-{
- // Negotiate all dimensions that require it
- ActorDimensionStack recursionStack;
-
- for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
- {
- const Dimension::Type dimension = static_cast< Dimension::Type >( 1 << i );
-
- // Negotiate
- NegotiateDimension( dimension, allocatedSize, recursionStack );
- }
-}
-
Vector2 Actor::ApplySizeSetPolicy( const Vector2& size )
{
return mRelayoutData->ApplySizeSetPolicy(*this, size);
void Actor::NegotiateSize( const Vector2& allocatedSize, RelayoutContainer& container )
{
- // Force a size negotiation for actors that has assigned size during relayout
- // This is required as otherwise the flags that force a relayout will not
- // necessarilly be set. This will occur if the actor has already been laid out.
- // The dirty flags are then cleared. Then if the actor is added back into the
- // relayout container afterwards, the dirty flags would still be clear...
- // causing a relayout to be skipped. Here we force any actors added to the
- // container to be relayed out.
- DALI_LOG_TIMER_START( NegSizeTimer1 );
-
- if( GetUseAssignedSize(Dimension::WIDTH ) )
- {
- SetLayoutNegotiated( false, Dimension::WIDTH );
- }
- if( GetUseAssignedSize( Dimension::HEIGHT ) )
- {
- SetLayoutNegotiated( false, Dimension::HEIGHT );
- }
-
- // Do the negotiation
- NegotiateDimensions( allocatedSize );
-
- // Set the actor size
- SetNegotiatedSize( container );
-
- // Negotiate down to children
- for( uint32_t i = 0, count = GetChildCount(); i < count; ++i )
- {
- ActorPtr child = GetChildAt( i );
-
- // Forces children that have already been laid out to be relayed out
- // if they have assigned size during relayout.
- if( child->GetUseAssignedSize(Dimension::WIDTH) )
- {
- child->SetLayoutNegotiated(false, Dimension::WIDTH);
- child->SetLayoutDirty(true, Dimension::WIDTH);
- }
-
- if( child->GetUseAssignedSize(Dimension::HEIGHT) )
- {
- child->SetLayoutNegotiated(false, Dimension::HEIGHT);
- child->SetLayoutDirty(true, Dimension::HEIGHT);
- }
-
- // Only relayout if required
- if( child->RelayoutRequired() )
- {
- container.Add( Dali::Actor( child.Get() ), mTargetSize.GetVectorXY() );
- }
- }
- DALI_LOG_TIMER_END( NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: ");
+ Relayouter::NegotiateSize(*this, allocatedSize, container);
}
void Actor::SetUseAssignedSize( bool use, Dimension::Type dimension )
void Actor::SetPreferredSize( const Vector2& size )
{
- EnsureRelayouter();
-
- // If valid width or height, then set the resize policy to FIXED
- // A 0 width or height may also be required so if the resize policy has not been changed, i.e. is still set to DEFAULT,
- // then change to FIXED as well
-
- if( size.width > 0.0f || GetResizePolicy( Dimension::WIDTH ) == ResizePolicy::DEFAULT )
- {
- SetResizePolicy( ResizePolicy::FIXED, Dimension::WIDTH );
- }
-
- if( size.height > 0.0f || GetResizePolicy( Dimension::HEIGHT ) == ResizePolicy::DEFAULT )
- {
- SetResizePolicy( ResizePolicy::FIXED, Dimension::HEIGHT );
- }
-
- mRelayoutData->preferredSize = size;
-
- mUseAnimatedSize = AnimatedSizeFlag::CLEAR;
-
- RelayoutRequest();
+ EnsureRelayouter().SetPreferredSize(*this, size);
}
Vector2 Actor::GetPreferredSize() const
}
}
-void Actor::SetSiblingOrder( uint32_t order )
+void Actor::EmitOrderChangedAndRebuild()
{
- if ( mParent )
+ Dali::Actor handle( this );
+ mParent->mChildOrderChangedSignal.Emit( handle );
+ if( mIsOnScene && mScene )
{
- ActorContainer& siblings = *(mParent->mChildren);
- uint32_t currentOrder = GetSiblingOrder();
-
- if( order != currentOrder )
- {
- if( order == 0 )
- {
- LowerToBottom();
- }
- else if( order < siblings.size() -1 )
- {
- if( order > currentOrder )
- {
- RaiseAbove( *siblings[order] );
- }
- else
- {
- LowerBelow( *siblings[order] );
- }
- }
- else
- {
- RaiseToTop();
- }
- }
+ mScene->RequestRebuildDepthTree();
}
}
-uint32_t Actor::GetSiblingOrder() const
+void Actor::SetSiblingOrder( uint32_t order )
{
- uint32_t order = 0;
-
- if ( mParent )
+ if( mParent && SiblingHandler::SetSiblingOrder(*(mParent->mChildren), *this, order))
{
- ActorContainer& siblings = *(mParent->mChildren);
- for( std::size_t i = 0; i < siblings.size(); ++i )
- {
- if( siblings[i] == this )
- {
- order = static_cast<uint32_t>( i );
- break;
- }
- }
+ EmitOrderChangedAndRebuild();
}
-
- return order;
}
-void Actor::RequestRebuildDepthTree()
+uint32_t Actor::GetSiblingOrder() const
{
- if( mIsOnScene )
+ uint32_t order = 0;
+ if( mParent )
{
- if( mScene )
- {
- mScene->RequestRebuildDepthTree();
- }
+ order = SiblingHandler::GetSiblingOrder(*(mParent->mChildren), *this);
}
+ return order;
}
void Actor::Raise()
{
- if ( mParent )
+ if( mParent && SiblingHandler::Raise(*(mParent->mChildren), *this) )
{
- ActorContainer& siblings = *(mParent->mChildren);
- if( siblings.back() != this ) // If not already at end
- {
- for( std::size_t i=0; i<siblings.size(); ++i )
- {
- if( siblings[i] == this )
- {
- // Swap with next
- ActorPtr next = siblings[i+1];
- siblings[i+1] = this;
- siblings[i] = next;
- break;
- }
- }
- }
-
- Dali::Actor handle( this );
- mParent->mChildOrderChangedSignal.Emit( handle );
-
- RequestRebuildDepthTree();
+ EmitOrderChangedAndRebuild();
}
else
{
void Actor::Lower()
{
- if ( mParent )
+ if( mParent && SiblingHandler::Lower(*(mParent->mChildren), *this) )
{
- ActorContainer& siblings = *(mParent->mChildren);
- if( siblings.front() != this ) // If not already at beginning
- {
- for( std::size_t i=1; i<siblings.size(); ++i )
- {
- if( siblings[i] == this )
- {
- // Swap with previous
- ActorPtr previous = siblings[i-1];
- siblings[i-1] = this;
- siblings[i] = previous;
- break;
- }
- }
- }
-
- Dali::Actor handle( this );
- mParent->mChildOrderChangedSignal.Emit( handle );
-
- RequestRebuildDepthTree();
+ EmitOrderChangedAndRebuild();
}
else
{
void Actor::RaiseToTop()
{
- if ( mParent )
+ if( mParent && SiblingHandler::RaiseToTop(*(mParent->mChildren), *this) )
{
- ActorContainer& siblings = *(mParent->mChildren);
- if( siblings.back() != this ) // If not already at end
- {
- auto iter = std::find( siblings.begin(), siblings.end(), this );
- if( iter != siblings.end() )
- {
- siblings.erase(iter);
- siblings.push_back(ActorPtr(this));
- }
- }
-
- Dali::Actor handle( this );
- mParent->mChildOrderChangedSignal.Emit( handle );
-
- RequestRebuildDepthTree();
+ EmitOrderChangedAndRebuild();
}
else
{
void Actor::LowerToBottom()
{
- if ( mParent )
+ if( mParent && SiblingHandler::LowerToBottom(*(mParent->mChildren), *this) )
{
- ActorContainer& siblings = *(mParent->mChildren);
- if( siblings.front() != this ) // If not already at bottom,
- {
- ActorPtr thisPtr(this); // ensure this actor remains referenced.
-
- auto iter = std::find( siblings.begin(), siblings.end(), this );
- if( iter != siblings.end() )
- {
- siblings.erase(iter);
- siblings.insert(siblings.begin(), thisPtr);
- }
- }
-
- Dali::Actor handle( this );
- mParent->mChildOrderChangedSignal.Emit( handle );
-
- RequestRebuildDepthTree();
+ EmitOrderChangedAndRebuild();
}
else
{
void Actor::RaiseAbove( Internal::Actor& target )
{
- if ( mParent )
+ if( mParent && SiblingHandler::RaiseAbove( *(mParent->mChildren), *this, target ))
{
- ActorContainer& siblings = *(mParent->mChildren);
- if( siblings.back() != this && target.mParent == mParent ) // If not already at top
- {
- ActorPtr thisPtr(this); // ensure this actor remains referenced.
-
- auto targetIter = std::find( siblings.begin(), siblings.end(), &target );
- auto thisIter = std::find( siblings.begin(), siblings.end(), this );
- if( thisIter < targetIter )
- {
- siblings.erase(thisIter);
- // Erasing early invalidates the targetIter. (Conversely, inserting first may also
- // invalidate thisIter)
- targetIter = std::find( siblings.begin(), siblings.end(), &target );
- ++targetIter;
- siblings.insert(targetIter, thisPtr);
- }
-
- Dali::Actor handle( this );
- mParent->mChildOrderChangedSignal.Emit( handle );
-
- RequestRebuildDepthTree();
- }
+ EmitOrderChangedAndRebuild();
}
else
{
void Actor::LowerBelow( Internal::Actor& target )
{
- if ( mParent )
+ if( mParent && SiblingHandler::LowerBelow(*(mParent->mChildren), *this, target ) )
{
- ActorContainer& siblings = *(mParent->mChildren);
- if( siblings.front() != this && target.mParent == mParent ) // If not already at bottom
- {
- ActorPtr thisPtr(this); // ensure this actor remains referenced.
-
- auto targetIter = std::find( siblings.begin(), siblings.end(), &target );
- auto thisIter = std::find( siblings.begin(), siblings.end(), this );
-
- if( thisIter > targetIter )
- {
- siblings.erase(thisIter); // this only invalidates iterators at or after this point.
- siblings.insert(targetIter, thisPtr);
- }
-
- Dali::Actor handle( this );
- mParent->mChildOrderChangedSignal.Emit( handle );
-
- RequestRebuildDepthTree();
- }
+ EmitOrderChangedAndRebuild();
}
else
{
class Renderer;
class Scene;
-using ActorContainer = std::vector<ActorPtr>;
-using ActorIter = ActorContainer::iterator;
-using ActorConstIter = ActorContainer::const_iterator;
-
using RendererContainer = std::vector<RendererPtr>;
using RendererIter = RendererContainer::iterator;
bool RelayoutDependentOnDimension( Dimension::Type dimension, Dimension::Type dependentDimension );
/**
- * Negotiate sizes for a control in all dimensions
- *
- * @param[in] allocatedSize The size constraint that the control must respect
- */
- void NegotiateDimensions( const Vector2& allocatedSize );
-
- /**
- * Negotiate size for a specific dimension
- *
- * The algorithm adopts a recursive dependency checking approach. Meaning, that wherever dependencies
- * are found, e.g. an actor dependent on its parent, the dependency will be calculated first with NegotiatedDimension and
- * LayoutDimensionNegotiated flags being filled in on the actor.
- *
- * @post All actors that exist in the dependency chain connected to the given actor will have had their NegotiatedDimensions
- * calculated and set as well as the LayoutDimensionNegotiated flags.
- *
- * @param[in] dimension The dimension to negotiate on
- * @param[in] allocatedSize The size constraint that the actor must respect
- */
- void NegotiateDimension( Dimension::Type dimension, const Vector2& allocatedSize, ActorDimensionStack& recursionStack );
-
- /**
* @brief Calculate the size of a dimension
*
* @param[in] dimension The dimension to calculate the size for
uint32_t GetSiblingOrder() const;
/**
- * Request that the stage rebuilds the actor depth indices.
+ * Emit ChildOrderChanged signal, and request that the scene
+ * rebuilds the actor depth indices.
*/
- void RequestRebuildDepthTree();
+ void EmitOrderChangedAndRebuild();
/**
* @brief Get the current position of the actor in screen coordinates.
static ActorContainer mNullChildren; ///< Empty container (shared by all actors, returned by GetChildren() const)
struct PropertyHandler;
+ struct SiblingHandler;
};
} // namespace Internal
#include <dali/public-api/math/vector3.h>
#include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogRelayoutFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_TIMER" );
+#endif
+} // unnamed namespace
+
namespace Dali
{
return false;
}
+void Actor::Relayouter::SetPreferredSize( Actor& actor, const Vector2& size )
+{
+ // If valid width or height, then set the resize policy to FIXED
+ // A 0 width or height may also be required so if the resize policy has not been changed, i.e. is still set to DEFAULT,
+ // then change to FIXED as well
+
+ if( size.width > 0.0f || GetResizePolicy( Dimension::WIDTH ) == ResizePolicy::DEFAULT )
+ {
+ actor.SetResizePolicy( ResizePolicy::FIXED, Dimension::WIDTH );
+ }
+
+ if( size.height > 0.0f || GetResizePolicy( Dimension::HEIGHT ) == ResizePolicy::DEFAULT )
+ {
+ actor.SetResizePolicy( ResizePolicy::FIXED, Dimension::HEIGHT );
+ }
+
+ actor.mRelayoutData->preferredSize = size;
+
+ actor.mUseAnimatedSize = AnimatedSizeFlag::CLEAR;
+
+ actor.RelayoutRequest();
+}
+
float Actor::Relayouter::ClampDimension( const Internal::Actor& actor, float size, Dimension::Type dimension )
{
const float minSize = actor.GetMinimumSize( dimension );
return std::max( minSize, std::min( size, maxSize ) );
}
+void Actor::Relayouter::NegotiateDimension( Actor& actor, Dimension::Type dimension, const Vector2& allocatedSize, Actor::ActorDimensionStack& recursionStack )
+{
+ // Check if it needs to be negotiated
+ if( actor.IsLayoutDirty( dimension ) && !actor.IsLayoutNegotiated( dimension ) )
+ {
+ // Check that we havn't gotten into an infinite loop
+ Actor::ActorDimensionPair searchActor = Actor::ActorDimensionPair( &actor, dimension );
+ bool recursionFound = false;
+ for( auto& element : recursionStack )
+ {
+ if( element == searchActor )
+ {
+ recursionFound = true;
+ break;
+ }
+ }
+
+ if( !recursionFound )
+ {
+ // Record the path that we have taken
+ recursionStack.push_back( Actor::ActorDimensionPair( &actor, dimension ) );
+
+ // Dimension dependency check
+ for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+ {
+ Dimension::Type dimensionToCheck = static_cast< Dimension::Type >( 1 << i );
+
+ if( actor.RelayoutDependentOnDimension( dimension, dimensionToCheck ) )
+ {
+ NegotiateDimension( actor, dimensionToCheck, allocatedSize, recursionStack );
+ }
+ }
+
+ // Parent dependency check
+ Actor* parent = actor.GetParent();
+ if( parent && actor.RelayoutDependentOnParent( dimension ) )
+ {
+ NegotiateDimension( *parent, dimension, allocatedSize, recursionStack );
+ }
+
+ // Children dependency check
+ if( actor.RelayoutDependentOnChildren( dimension ) )
+ {
+ for( uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i )
+ {
+ ActorPtr child = actor.GetChildAt( i );
+
+ // Only relayout child first if it is not dependent on this actor
+ if( !child->RelayoutDependentOnParent( dimension ) )
+ {
+ NegotiateDimension( *child, dimension, allocatedSize, recursionStack );
+ }
+ }
+ }
+
+ // For deriving classes
+ actor.OnCalculateRelayoutSize( dimension );
+
+ // All dependencies checked, calculate the size and set negotiated flag
+ const float newSize = ClampDimension( actor, actor.CalculateSize( dimension, allocatedSize ), dimension );
+
+ actor.SetNegotiatedDimension( newSize, dimension );
+ actor.SetLayoutNegotiated( true, dimension );
+
+ // For deriving classes
+ actor.OnLayoutNegotiated( newSize, dimension );
+
+ // This actor has been successfully processed, pop it off the recursion stack
+ recursionStack.pop_back();
+ }
+ else
+ {
+ // TODO: Break infinite loop
+ actor.SetLayoutNegotiated( true, dimension );
+ }
+ }
+}
+
+void Actor::Relayouter::NegotiateDimensions(Actor& actor, const Vector2& allocatedSize)
+{
+ // Negotiate all dimensions that require it
+ ActorDimensionStack recursionStack;
+
+ for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+ {
+ const Dimension::Type dimension = static_cast< Dimension::Type >( 1 << i );
+
+ // Negotiate
+ NegotiateDimension(actor, dimension, allocatedSize, recursionStack);
+ }
+}
+
+void Actor::Relayouter::NegotiateSize(Actor& actor, const Vector2& allocatedSize, RelayoutContainer& container)
+{
+ // Force a size negotiation for actors that has assigned size during relayout
+ // This is required as otherwise the flags that force a relayout will not
+ // necessarilly be set. This will occur if the actor has already been laid out.
+ // The dirty flags are then cleared. Then if the actor is added back into the
+ // relayout container afterwards, the dirty flags would still be clear...
+ // causing a relayout to be skipped. Here we force any actors added to the
+ // container to be relayed out.
+ DALI_LOG_TIMER_START( NegSizeTimer1 );
+
+ if( actor.GetUseAssignedSize(Dimension::WIDTH ) )
+ {
+ actor.SetLayoutNegotiated( false, Dimension::WIDTH );
+ }
+ if( actor.GetUseAssignedSize( Dimension::HEIGHT ) )
+ {
+ actor.SetLayoutNegotiated( false, Dimension::HEIGHT );
+ }
+
+ // Do the negotiation
+ NegotiateDimensions(actor, allocatedSize);
+
+ // Set the actor size
+ actor.SetNegotiatedSize( container );
+
+ // Negotiate down to children
+ for( uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i )
+ {
+ ActorPtr child = actor.GetChildAt( i );
+
+ // Forces children that have already been laid out to be relayed out
+ // if they have assigned size during relayout.
+ if( child->GetUseAssignedSize(Dimension::WIDTH) )
+ {
+ child->SetLayoutNegotiated(false, Dimension::WIDTH);
+ child->SetLayoutDirty(true, Dimension::WIDTH);
+ }
+
+ if( child->GetUseAssignedSize(Dimension::HEIGHT) )
+ {
+ child->SetLayoutNegotiated(false, Dimension::HEIGHT);
+ child->SetLayoutDirty(true, Dimension::HEIGHT);
+ }
+
+ // Only relayout if required
+ if( child->RelayoutRequired() )
+ {
+ container.Add( Dali::Actor( child.Get() ), actor.mTargetSize.GetVectorXY() );
+ }
+ }
+ DALI_LOG_TIMER_END( NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: ");
+}
+
} // namespace Internal
} // namespace Dali
/// @copydoc Actor::IsLayoutDirty
bool IsLayoutDirty( Dimension::Type dimension ) const;
+ /// @copydoc Actor::SetPreferredSize
+ /// @actor[in] actor The Actor whose preferred size we wish to set
+ void SetPreferredSize( Actor& actor, const Vector2& size );
+
/**
* @brief Clamp a dimension given the relayout constraints on given actor
*
*/
static float ClampDimension( const Internal::Actor& actor, float size, Dimension::Type dimension );
+ /**
+ * Negotiate size for a specific dimension
+ *
+ * The algorithm adopts a recursive dependency checking approach. Meaning, that wherever dependencies
+ * are found, e.g. an actor dependent on its parent, the dependency will be calculated first with NegotiatedDimension and
+ * LayoutDimensionNegotiated flags being filled in on the actor.
+ *
+ * @post All actors that exist in the dependency chain connected to the given actor will have had their NegotiatedDimensions
+ * calculated and set as well as the LayoutDimensionNegotiated flags.
+ *
+ * @param[in] actor The actor whose dimension we are negotiating
+ * @param[in] dimension The dimension to negotiate on
+ * @param[in] allocatedSize The size constraint that the actor must respect
+ */
+ static void NegotiateDimension(Actor& actor, Dimension::Type dimension, const Vector2& allocatedSize, Actor::ActorDimensionStack& recursionStack);
+
+ /**
+ * Negotiate sizes for a control in all dimensions
+ *
+ * @param[in] actor The actor whose dimensions we are negotiating
+ * @param[in] allocatedSize The size constraint that the control must respect
+ */
+ static void NegotiateDimensions(Actor& actor, const Vector2& allocatedSize);
+
+ /**
+ * @brief Called by the RelayoutController to negotiate the size of an actor.
+ *
+ * The size allocated by the the algorithm is passed in which the
+ * actor must adhere to. A container is passed in as well which
+ * the actor should populate with actors it has not / or does not
+ * need to handle in its size negotiation.
+ *
+ * @param[in] actor The actor whose size we are negotiating
+ * @param[in] size The allocated size.
+ * @param[in,out] container The container that holds actors that are fed back into the
+ * RelayoutController algorithm.
+ */
+ static void NegotiateSize(Actor& actor, const Vector2& allocatedSize, RelayoutContainer& container);
+
public:
ResizePolicy::Type resizePolicies[ Dimension::DIMENSION_COUNT ]; ///< Resize policies
--- /dev/null
+/*
+ * Copyright (c) 2020 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.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/event/actors/actor-siblings.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+
+namespace Dali
+{
+namespace Internal
+{
+
+bool Actor::SiblingHandler::SetSiblingOrder(
+ ActorContainer& siblings,
+ Actor& actor,
+ uint32_t order )
+{
+ bool changed = false;
+
+ uint32_t currentOrder = GetSiblingOrder(siblings, actor);
+ if( order != currentOrder )
+ {
+ if( order == 0 )
+ {
+ changed = LowerToBottom(siblings, actor);
+ }
+ else if( order < siblings.size() -1 )
+ {
+ if( order > currentOrder )
+ {
+ changed = RaiseAbove( siblings, actor, *siblings[order] );
+ }
+ else
+ {
+ changed = LowerBelow( siblings, actor, *siblings[order] );
+ }
+ }
+ else
+ {
+ changed = RaiseToTop(siblings, actor);
+ }
+ }
+ return changed;
+}
+
+uint32_t Actor::SiblingHandler::GetSiblingOrder(const ActorContainer& siblings, const Actor& actor)
+{
+ uint32_t order=0;
+ for( std::size_t i = 0; i < siblings.size(); ++i )
+ {
+ if( siblings[i] == &actor )
+ {
+ order = static_cast<uint32_t>( i );
+ break;
+ }
+ }
+ return order;
+}
+
+bool Actor::SiblingHandler::Raise(ActorContainer& siblings, Actor& actor)
+{
+ bool changed = false;
+ if( siblings.back() != &actor ) // If not already at end
+ {
+ for( std::size_t i=0; i<siblings.size(); ++i )
+ {
+ if( siblings[i] == &actor )
+ {
+ // Swap with next
+ ActorPtr next = siblings[i+1];
+ siblings[i+1] = &actor;
+ siblings[i] = next;
+ changed = true;
+ break;
+ }
+ }
+ }
+ return changed;
+}
+
+bool Actor::SiblingHandler::Lower(ActorContainer& siblings, Actor& actor)
+{
+ bool changed = false;
+ if( siblings.front() != &actor ) // If not already at beginning
+ {
+ for( std::size_t i=1; i<siblings.size(); ++i )
+ {
+ if( siblings[i] == &actor )
+ {
+ // Swap with previous
+ ActorPtr previous = siblings[i-1];
+ siblings[i-1] = &actor;
+ siblings[i] = previous;
+ changed = true;
+ break;
+ }
+ }
+ }
+ return changed;
+}
+
+bool Actor::SiblingHandler::RaiseToTop(ActorContainer& siblings, Actor& actor)
+{
+ bool changed = false;
+ if( siblings.back() != &actor ) // If not already at end
+ {
+ auto iter = std::find( siblings.begin(), siblings.end(), &actor );
+ if( iter != siblings.end() )
+ {
+ siblings.erase(iter);
+ siblings.push_back(ActorPtr(&actor));
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+bool Actor::SiblingHandler::LowerToBottom(ActorContainer& siblings, Actor& actor)
+{
+ bool changed = false;
+ if( siblings.front() != &actor ) // If not already at bottom,
+ {
+ ActorPtr actorPtr(&actor); // ensure actor actor remains referenced.
+
+ auto iter = std::find( siblings.begin(), siblings.end(), &actor );
+ if( iter != siblings.end() )
+ {
+ siblings.erase(iter);
+ siblings.insert(siblings.begin(), actorPtr);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+bool Actor::SiblingHandler::RaiseAbove(ActorContainer& siblings, Actor& actor, Actor& target)
+{
+ bool raised = false;
+ if( siblings.back() != &actor && target.GetParent() == actor.GetParent() ) // If not already at top
+ {
+ ActorPtr actorPtr(&actor); // ensure actor actor remains referenced.
+
+ auto targetIter = std::find( siblings.begin(), siblings.end(), &target );
+ auto actorIter = std::find( siblings.begin(), siblings.end(), &actor );
+ if( actorIter < targetIter )
+ {
+ siblings.erase(actorIter);
+ // Erasing early invalidates the targetIter. (Conversely, inserting first may also
+ // invalidate actorIter)
+ targetIter = std::find( siblings.begin(), siblings.end(), &target );
+ ++targetIter;
+ siblings.insert(targetIter, actorPtr);
+ }
+ raised = true;
+ }
+ return raised;
+}
+
+bool Actor::SiblingHandler::LowerBelow(ActorContainer& siblings, Actor& actor, Actor& target)
+{
+ bool lowered = false;
+
+ // If not already at bottom
+ if( siblings.front() != &actor && target.GetParent() == actor.GetParent() )
+ {
+ ActorPtr actorPtr(&actor); // ensure actor actor remains referenced.
+
+ auto targetIter = std::find( siblings.begin(), siblings.end(), &target );
+ auto actorIter = std::find( siblings.begin(), siblings.end(), &actor );
+
+ if( actorIter > targetIter )
+ {
+ siblings.erase(actorIter); // actor only invalidates iterators at or after actor point.
+ siblings.insert(targetIter, actorPtr);
+ }
+ lowered = true;
+ }
+ return lowered;
+}
+
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_ACTOR_SIBLINGS_H
+#define DALI_INTERNAL_ACTOR_SIBLINGS_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use actor 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.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/actors/actor-impl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+
+struct Actor::SiblingHandler
+{
+ /**
+ * @brief Change the sibling order of the given actor.
+ *
+ * @param[in,out] siblings The container of siblings
+ * @param[in] actor The actor to change
+ * @param[in] order The new order for the actor
+ * @return true if order has been modified
+ */
+ static bool SetSiblingOrder( ActorContainer& siblings, Actor& actor, uint32_t order );
+
+ /**
+ * @brief Get the sibling order of the given actor.
+ *
+ * @param[in] siblings The container of siblings
+ * @param[in] actor The actor to query
+ * @return the order in the sibling array of the actor
+ */
+ static uint32_t GetSiblingOrder(const ActorContainer& siblings, const Actor& actor);
+
+ /**
+ * @brief Raise the actor within the siblings list by one
+ * @param[in,out] siblings The container of siblings
+ * @param[in] actor The actor to move
+ * @return true if order has been modified
+ */
+ static bool Raise(ActorContainer& siblings, Actor& actor);
+
+ /**
+ * @brief Lower the actor within the siblings list by one
+ * @param[in,out] siblings The container of siblings
+ * @param[in] actor The actor to move
+ * @return true if order has been modified
+ */
+ static bool Lower(ActorContainer& siblings, Actor& actor);
+
+ /**
+ * @brief Raise the actor to the top of the siblings list.
+ *
+ * @param[in,out] siblings The container of siblings
+ * @param[in] actor The actor to move
+ * @return true if order has been modified
+ */
+ static bool RaiseToTop(ActorContainer& siblings, Actor& actor);
+
+ /**
+ * @brief Lower the actor to the bottom of the siblings list.
+ *
+ * @param[in,out] siblings The container of siblings
+ * @param[in] actor The actor to move
+ * @return true if order has been modified
+ */
+ static bool LowerToBottom(ActorContainer& siblings, Actor& actor);
+
+ /**
+ * @brief Raise the actor above the target actor within the siblings list.
+ *
+ * @param[in,out] siblings The container of siblings
+ * @param[in] actor The actor to move
+ * @param[in] target The target actor
+ * @return true if order has been modified
+ */
+ static bool RaiseAbove(ActorContainer& siblings, Actor& actor, Actor& target);
+
+ /**
+ * @brief Lower the actor below the target actor within the siblings list.
+ *
+ * @param[in,out] siblings The container of siblings
+ * @param[in] actor The actor to move
+ * @param[in] target The target actor
+ * @return true if order has been modified
+ */
+ static bool LowerBelow(ActorContainer& siblings, Actor& actor, Actor& target);
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+
+#endif
#include <dali/internal/event/common/property-notification-impl.h>
#include <dali/internal/event/common/stage-impl.h>
#include <dali/internal/event/common/type-registry-impl.h>
+#include <dali/internal/common/const-string.h>
using Dali::Internal::SceneGraph::AnimatableProperty;
using Dali::Internal::SceneGraph::PropertyBase;
return count;
}
-std::string Object::GetPropertyName( Property::Index index ) const
+std::string_view Object::GetPropertyName(Property::Index index) const
{
DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
CustomPropertyMetadata* custom = FindCustomProperty( index );
if( custom )
{
- return custom->name;
+ return custom->name.GetStringView();
}
}
DALI_LOG_ERROR( "Property index %d not found\n", index );
- return std::string();
+ return {};
}
-Property::Index Object::GetPropertyIndex( Property::Key key ) const
+Property::Index Object::GetPropertyIndex(KeyRef key) const
{
Property::Index index = Property::INVALID_INDEX;
- if( key.type == Property::Key::STRING )
+ if(key.mType == Property::Key::STRING)
{
const TypeInfo* typeInfo( GetTypeInfo() );
if ( typeInfo )
{
- index = typeInfo->GetPropertyIndex( key.stringKey );
+ index = typeInfo->GetPropertyIndex(key.mString);
}
}
{
CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
- if( ( key.type == Property::Key::STRING && custom->name == key.stringKey) ||
- ( key.type == Property::Key::INDEX && custom->key == key.indexKey ) )
+ if((key.mType == Property::Key::STRING && custom->name == key.mString) ||
+ (key.mType == Property::Key::INDEX && custom->key == key.mIndex))
{
if ( custom->childPropertyIndex != Property::INVALID_INDEX )
{
if( !custom )
{
// If the child property is not registered yet, register it.
- custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
+ custom = new CustomPropertyMetadata({}, propertyValue, Property::READ_WRITE);
mCustomProperties.PushBack( custom );
}
const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
if( parentTypeInfo )
{
- custom->name = parentTypeInfo->GetChildPropertyName( index );
+ custom->name = ConstString(parentTypeInfo->GetChildPropertyName(index));
}
}
}
}
}
-Property::Index Object::RegisterProperty(std::string name, Property::Value propertyValue)
+Property::Index Object::RegisterProperty(std::string_view name, Property::Value propertyValue)
{
- return RegisterProperty(std::move(name), Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE);
+ return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE);
}
-Property::Index Object::RegisterProperty(std::string name, Property::Index key, Property::Value propertyValue)
+Property::Index Object::RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue)
{
- return RegisterProperty(std::move(name), key, std::move(propertyValue), Property::ANIMATABLE);
+ return RegisterProperty(name, key, std::move(propertyValue), Property::ANIMATABLE);
}
void Object::SetProperties( const Property::Map& properties )
}
}
-Property::Index Object::RegisterProperty(std::string name,
+Property::Index Object::RegisterProperty(std::string_view name,
Property::Value propertyValue,
Property::AccessMode accessMode)
{
- return RegisterProperty(std::move(name), Property::INVALID_KEY, std::move(propertyValue), accessMode);
+ return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), accessMode);
}
-Property::Index Object::RegisterProperty(std::string name,
+Property::Index Object::RegisterProperty(std::string_view name,
Property::Index key,
Property::Value propertyValue,
Property::AccessMode accessMode)
{
+ auto constString = ConstString(name);
// If property with the required key already exists, then just set it.
Property::Index index = Property::INVALID_INDEX;
if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
}
if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
{
- index = GetPropertyIndex( name );
+ index = GetPropertyIndex(constString);
}
if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
if( Property::ANIMATABLE == accessMode )
{
index = RegisterSceneGraphProperty(
- name,
+ constString,
key,
PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
std::move(propertyValue));
- AddUniformMapping(index, std::move(name));
+ AddUniformMapping(index, constString);
}
else
{
index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() );
CustomPropertyMetadata* customProperty =
- new CustomPropertyMetadata(std::move(name), std::move(propertyValue), accessMode);
+ new CustomPropertyMetadata(constString, std::move(propertyValue), accessMode);
// Resolve index for the child property
Object* parent = GetParentObject();
const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
if( parentTypeInfo )
{
- Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
+ Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
if( childPropertyIndex != Property::INVALID_INDEX )
{
customProperty->childPropertyIndex = childPropertyIndex;
}
}
-void Object::AddUniformMapping(Property::Index propertyIndex, std::string uniformName) const
+void Object::AddUniformMapping(Property::Index propertyIndex, ConstString uniformName) const
{
// Get the address of the property if it's a scene property
const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
{
const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
- OwnerPointer<SceneGraph::UniformPropertyMapping> map =
- new SceneGraph::UniformPropertyMapping(std::move(uniformName), propertyPtr);
+ SceneGraph::UniformPropertyMapping map(uniformName, propertyPtr);
// Message takes ownership of Uniform map (and will delete it after copy)
AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map );
}
void Object::RemoveUniformMapping( const std::string& uniformName ) const
{
const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
- RemoveUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, uniformName);
+ RemoveUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, ConstString(uniformName));
}
void Object::ApplyConstraint( ConstraintBase& constraint )
return nullptr;
}
-Property::Index Object::RegisterSceneGraphProperty( std::string name, Property::Index key, Property::Index index, Property::Value propertyValue ) const
+Property::Index Object::RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const
{
// Create a new property
Dali::Internal::OwnerPointer<PropertyBase> newProperty;
{
DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
- mCustomProperties.PushBack( new CustomPropertyMetadata( std::move(name), key, std::move(propertyValue), property ) );
+ mCustomProperties.PushBack(new CustomPropertyMetadata(name, key, std::move(propertyValue), property));
}
else
{
const Property::Value* value ) const
{
// If the property is not a component of a base property, register the whole property itself.
- const std::string& propertyName = typeInfo.GetPropertyName( index );
+ auto propertyName = ConstString(typeInfo.GetPropertyName(index));
Property::Value initialValue;
if( value )
{
{
CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( entry );
- if( customProperty->name.empty() )
+ if(customProperty->name.IsEmpty())
{
if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
{
// Resolve name for any child property with no name
- customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
+ customProperty->name = ConstString(parentTypeInfo->GetChildPropertyName(customProperty->childPropertyIndex));
}
}
else
{
- Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
+ Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
if( childPropertyIndex != Property::INVALID_INDEX )
{
// Resolve index for any property with a name that matches the parent's child property name
#include <cstdint> // uint32_t
// INTERNAL INCLUDES
+#include <dali/devel-api/common/owner-container.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/internal/common/const-string.h>
+#include <dali/internal/event/animation/animation-impl.h>
+#include <dali/internal/event/common/event-thread-services.h>
+#include <dali/internal/event/common/property-input-impl.h>
+#include <dali/internal/event/common/property-metadata.h>
+#include <dali/internal/update/common/property-base.h>
#include <dali/public-api/animation/constraint.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/common/vector-wrapper.h>
#include <dali/public-api/object/base-object.h>
#include <dali/public-api/object/handle.h>
-#include <dali/public-api/object/property.h>
#include <dali/public-api/object/property-index-ranges.h>
#include <dali/public-api/object/property-input.h>
#include <dali/public-api/object/property-map.h>
#include <dali/public-api/object/property-notification.h>
-#include <dali/devel-api/common/owner-container.h>
-#include <dali/devel-api/object/handle-devel.h>
-#include <dali/internal/event/animation/animation-impl.h>
-#include <dali/internal/event/common/event-thread-services.h>
-#include <dali/internal/event/common/property-input-impl.h>
-#include <dali/internal/event/common/property-metadata.h>
-#include <dali/internal/update/common/property-base.h>
+#include <dali/public-api/object/property.h>
namespace Dali
{
using ConstraintIter = ConstraintContainer::iterator;
using ConstraintConstIter = ConstraintContainer::const_iterator;
+class KeyRef
+{
+public:
+ KeyRef(const Property::Key& key)
+ : mType(key.type)
+ {
+ if(mType == Property::Key::STRING)
+ {
+ mString = ConstString(key.stringKey);
+ }
+ else
+ {
+ mIndex = key.indexKey;
+ }
+ }
+ KeyRef(ConstString str)
+ : mType(Property::Key::STRING)
+ {
+ mString = str;
+ }
+ KeyRef(Property::Index index)
+ : mType(Property::Key::INDEX)
+ {
+ mIndex = index;
+ }
+ Property::Key::Type mType;
+ Property::Index mIndex{Property::INVALID_INDEX};
+ ConstString mString;
+};
+
/**
* A base class for objects which optionally provide properties.
* The concrete derived class is responsible for implementing the property system methods.
/**
* @copydoc Dali::Handle::GetPropertyName()
*/
- std::string GetPropertyName( Property::Index index ) const;
+ std::string_view GetPropertyName(Property::Index index) const;
/**
* @copydoc Dali::Handle::GetPropertyIndex()
*/
- Property::Index GetPropertyIndex( Property::Key key ) const;
+ Property::Index GetPropertyIndex(KeyRef key) const;
/**
* @copydoc Dali::Handle::IsPropertyWritable()
/**
* @copydoc Dali::Handle::RegisterProperty()
*/
- Property::Index RegisterProperty(std::string name, Property::Value propertyValue);
+ Property::Index RegisterProperty(std::string_view name, Property::Value propertyValue);
/**
* @copydoc Dali::Handle::RegisterProperty()
*/
- Property::Index RegisterProperty(std::string name, Property::Index key, Property::Value propertyValue);
+ Property::Index RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue);
/**
* @copydoc Dali::DevelHandle::SetProperties()
/**
* @copydoc Dali::Handle::RegisterProperty(std::string name, Property::Value propertyValue, Property::AccessMode accessMode)
*/
- Property::Index RegisterProperty(std::string name, Property::Value propertyValue, Property::AccessMode accessMode);
+ Property::Index RegisterProperty(std::string_view name, Property::Value propertyValue, Property::AccessMode accessMode);
/**
* @brief Implementing method for this override
*/
- Property::Index RegisterProperty(std::string name,
+ Property::Index RegisterProperty(std::string_view name,
Property::Index key,
Property::Value propertyValue,
Property::AccessMode accessMode);
* @param propertyIndex index of the property
* @param uniformName name of the uniform (same as property name)
*/
- void AddUniformMapping(Property::Index propertyIndex, std::string uniformName) const;
+ void AddUniformMapping(Property::Index propertyIndex, ConstString uniformName) const;
/**
* Removes uniform mapping for given property
* @param [in] value The value of the property.
* @return The index of the registered property or Property::INVALID_INDEX if registration failed.
*/
- Property::Index RegisterSceneGraphProperty( std::string name, Property::Index key, Property::Index index, Property::Value propertyValue ) const;
+ Property::Index RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const;
/**
* Registers animatable scene property
#include <utility>
// INTERNAL INCLUDES
+#include <dali/internal/common/const-string.h>
#include <dali/public-api/common/constants.h>
-#include <dali/public-api/object/property.h>
#include <dali/public-api/object/property-value.h>
+#include <dali/public-api/object/property.h>
namespace Dali
{
*
* @note A valid sceneGraphProperty is mandatory otherwise this will debug assert.
*/
- CustomPropertyMetadata( std::string propertyName,
- Property::Index propertyKey,
- Property::Value propertyValue,
- const SceneGraph::PropertyBase* sceneGraphProperty )
- : PropertyMetadata( std::move(propertyValue), sceneGraphProperty, true ),
- name( std::move(propertyName) ),
- key( propertyKey ),
- childPropertyIndex( Property::INVALID_INDEX )
+ CustomPropertyMetadata(ConstString propertyName,
+ Property::Index propertyKey,
+ Property::Value propertyValue,
+ const SceneGraph::PropertyBase* sceneGraphProperty)
+ : PropertyMetadata(std::move(propertyValue), sceneGraphProperty, true),
+ name(propertyName),
+ key(propertyKey),
+ childPropertyIndex(Property::INVALID_INDEX)
{
DALI_ASSERT_DEBUG( sceneGraphProperty && "Uninitialized scene-graph property" );
}
*
* @note The access mode MUST NOT be animatable otherwise this will debug assert.
*/
- CustomPropertyMetadata( std::string propertyName,
- Property::Value propertyValue,
- Property::AccessMode accessMode )
- : PropertyMetadata( std::move(propertyValue), nullptr, ( accessMode != Property::READ_ONLY ) ),
- name( std::move(propertyName) ),
- key( Property::INVALID_KEY ),
- childPropertyIndex( Property::INVALID_INDEX )
+ CustomPropertyMetadata(ConstString propertyName,
+ Property::Value propertyValue,
+ Property::AccessMode accessMode)
+ : PropertyMetadata(std::move(propertyValue), nullptr, (accessMode != Property::READ_ONLY)),
+ name(propertyName),
+ key(Property::INVALID_KEY),
+ childPropertyIndex(Property::INVALID_INDEX)
{
DALI_ASSERT_DEBUG( accessMode != Property::ANIMATABLE && "Event side only properties should not be animatable" );
}
CustomPropertyMetadata& operator=( const CustomPropertyMetadata& );
public: // Data
-
- std::string name; ///< The name of the property.
+ ConstString name; ///< The name of the property.
Property::Index key; ///< The key of the property.
Property::Index childPropertyIndex; ///< The index as a child property.
};
template <typename T>
struct PropertyNameFinder
{
- PropertyNameFinder( const std::string& find )
- : mFind( find )
+ PropertyNameFinder(ConstString find)
+ : mFind(find)
{
}
}
private:
-
- const std::string& mFind;
+ ConstString mFind;
};
/**
}
}
-const std::string& TypeInfo::GetRegisteredPropertyName( Property::Index index ) const
+std::string_view TypeInfo::GetRegisteredPropertyName(Property::Index index) const
{
RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
if ( iter != mRegisteredProperties.end() )
{
- return iter->second.name;
+ return iter->second.name.GetStringView();
}
if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
{
return empty;
}
-std::string TypeInfo::GetPropertyName( Property::Index index ) const
+std::string_view TypeInfo::GetPropertyName(Property::Index index) const
{
- std::string propertyName;
+ std::string_view propertyName;
// default or custom
if ( mDefaultProperties && ( index < DEFAULT_PROPERTY_MAX_COUNT ) )
{
PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
if ( iter != mRegisteredProperties.end() )
{
- return iter->second.name;
+ return iter->second.name.GetStringView();
}
}
// if not our property, go to parent
if ( iter == mRegisteredProperties.end() )
{
- mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+ mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
}
else
{
if ( iter == mRegisteredProperties.end() )
{
- mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+ mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
}
else
{
if ( iter == mRegisteredProperties.end() )
{
- mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+ mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
}
else
{
if ( iter == mRegisteredProperties.end() )
{
- mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(defaultValue.GetType(), std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+ mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(defaultValue.GetType(), ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
mPropertyDefaultValues.push_back(PropertyDefaultValuePair(index, std::move(defaultValue)));
}
else
if ( iter == mRegisteredProperties.end() )
{
- mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), baseIndex, componentIndex)));
+ mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), baseIndex, componentIndex)));
success = true;
}
}
if ( iter == mRegisteredChildProperties.end() )
{
- mRegisteredChildProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+ mRegisteredChildProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
}
else
{
return count;
}
-Property::Index TypeInfo::GetPropertyIndex( const std::string& name ) const
+Property::Index TypeInfo::GetPropertyIndex(ConstString name) const
{
Property::Index index = Property::INVALID_INDEX;
bool found = false;
// check default properties
if( mDefaultProperties )
{
+ auto stringView = name.GetStringView();
for( Property::Index tableIndex = 0; tableIndex < mDefaultPropertyCount; ++tableIndex )
{
- if(mDefaultProperties[tableIndex].name == name)
+ if(mDefaultProperties[tableIndex].name == stringView)
{
index = mDefaultProperties[ tableIndex ].enumIndex;
found = true;
return componentIndex;
}
-Property::Index TypeInfo::GetChildPropertyIndex( const std::string& name ) const
+Property::Index TypeInfo::GetChildPropertyIndex(ConstString name) const
{
Property::Index index = Property::INVALID_INDEX;
return index;
}
-const std::string& TypeInfo::GetChildPropertyName( Property::Index index ) const
+std::string_view TypeInfo::GetChildPropertyName(Property::Index index) const
{
RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
if ( iter != mRegisteredChildProperties.end() )
{
- return iter->second.name;
+ return iter->second.name.GetStringView();
}
if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
DALI_LOG_ERROR( "Property index %d not found\n", index );
- static std::string empty;
- return empty;
+ return {};
}
Property::Type TypeInfo::GetChildPropertyType( Property::Index index ) const
if( mCSharpType )
{
// CSharp wants a property name not an index
- const std::string& name = (iter->second).name;
+ auto name = (iter->second).name;
- iter->second.cSharpSetFunc( object,name.c_str(), const_cast< Property::Value* >(&value) );
+ iter->second.cSharpSetFunc(object, name.GetCString(), const_cast<Property::Value*>(&value));
}
else
{
void TypeInfo::SetProperty(BaseObject* object, const std::string& name, Property::Value value) const
{
- RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
- PropertyNameFinder< RegisteredPropertyPair >( name ) );
+ RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(ConstString(name)));
if ( iter != mRegisteredProperties.end() )
{
DALI_ASSERT_ALWAYS( iter->second.setFunc && "Trying to write to a read-only property" );
// CSharp wants a property name not an index
// CSharp callback can't return an object by value, it can only return a pointer
// CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
- const std::string& name = (iter->second).name;
-
- return *( iter->second.cSharpGetFunc( const_cast< BaseObject* >( object ), name.c_str()) );
+ auto name = (iter->second).name;
+ return *(iter->second.cSharpGetFunc(const_cast<BaseObject*>(object), name.GetCString()));
}
else
{
Property::Value TypeInfo::GetProperty( const BaseObject *object, const std::string& name ) const
{
- RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
- PropertyNameFinder< RegisteredPropertyPair >( name ) );
-
-
+ RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(ConstString(name)));
if( iter != mRegisteredProperties.end() )
{
#include <string>
// INTERNAL INCLUDES
+#include <dali/devel-api/object/csharp-type-info.h>
+#include <dali/internal/common/const-string.h>
+#include <dali/internal/event/object/default-property-metadata.h>
#include <dali/public-api/object/base-handle.h>
#include <dali/public-api/object/base-object.h>
-#include <dali/public-api/object/type-info.h>
#include <dali/public-api/object/property.h>
-#include <dali/devel-api/object/csharp-type-info.h>
-#include <dali/internal/event/object/default-property-metadata.h>
+#include <dali/public-api/object/type-info.h>
namespace Dali
{
* @copydoc Dali::TypeInfo::GetPropertyName() const
* this API exists to keep the old public API, which cannot be changed
*/
- const std::string& GetRegisteredPropertyName( Property::Index index ) const;
+ std::string_view GetRegisteredPropertyName(Property::Index index) const;
/**
* Returns the property name for given index
* @param index of the property
* @return name or empty string
*/
- std::string GetPropertyName( Property::Index index ) const;
+ std::string_view GetPropertyName(Property::Index index) const;
/*
* Add an action function
* @param[in] name The name of the property.
* @return The index associated with that name.
*/
- Property::Index GetPropertyIndex( const std::string& name ) const;
+ Property::Index GetPropertyIndex(ConstString name) const;
/**
* Given a property index, retrieve the index of its base property.
* @param[in] name The name of the child property.
* @return The index associated with that name.
*/
- Property::Index GetChildPropertyIndex( const std::string& name ) const;
+ Property::Index GetChildPropertyIndex(ConstString name) const;
/**
* Retrieve the name of the child property at the given index.
* @param[in] index The property index.
* @return The name of the child property.
*/
- const std::string& GetChildPropertyName( Property::Index index ) const;
+ std::string_view GetChildPropertyName(Property::Index index) const;
/**
* Retrieve the Property::Type of the child property at the given index.
struct RegisteredProperty
{
- RegisteredProperty(Property::Type propType, std::string propName, Property::Index basePropertyIndex, int32_t componentIndex)
+ RegisteredProperty(Property::Type propType, ConstString propName, Property::Index basePropertyIndex, int32_t componentIndex)
: type(propType),
setFunc(nullptr),
getFunc(nullptr),
- name(std::move(propName)),
+ name(propName),
basePropertyIndex(basePropertyIndex),
componentIndex(componentIndex)
{
}
- RegisteredProperty(Property::Type propType, Dali::TypeInfo::SetPropertyFunction set, Dali::TypeInfo::GetPropertyFunction get, std::string propName, Property::Index basePropertyIndex, int componentIndex)
+ RegisteredProperty(Property::Type propType, Dali::TypeInfo::SetPropertyFunction set, Dali::TypeInfo::GetPropertyFunction get, ConstString propName, Property::Index basePropertyIndex, int componentIndex)
: type(propType),
setFunc(set),
getFunc(get),
- name(std::move(propName)),
+ name(propName),
basePropertyIndex(basePropertyIndex),
componentIndex(componentIndex)
{
}
- RegisteredProperty(Property::Type propType, Dali::CSharpTypeInfo::SetPropertyFunction set, Dali::CSharpTypeInfo::GetPropertyFunction get, std::string propName, Property::Index basePropertyIndex, int componentIndex)
+ RegisteredProperty(Property::Type propType, Dali::CSharpTypeInfo::SetPropertyFunction set, Dali::CSharpTypeInfo::GetPropertyFunction get, ConstString propName, Property::Index basePropertyIndex, int componentIndex)
: type(propType),
cSharpSetFunc(set),
cSharpGetFunc(get),
- name(std::move(propName)),
+ name(propName),
basePropertyIndex(basePropertyIndex),
componentIndex(componentIndex)
{
Dali::TypeInfo::GetPropertyFunction getFunc = nullptr;
Dali::CSharpTypeInfo::GetPropertyFunction cSharpGetFunc; // only one field can be initialized but this will have same value anyways
};
- std::string name;
+ ConstString name;
Property::Index basePropertyIndex = Property::INVALID_INDEX;
int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
};
{
continue;
}
- format->components[i].name = component.first.stringKey;
+ format->components[i].name = ConstString(component.first.stringKey);
// enums are stored in the map as int
Property::Type type = Property::Type( component.second.Get<int>() );
${internal_src_dir}/common/image-sampler.cpp
${internal_src_dir}/common/image-attributes.cpp
${internal_src_dir}/common/fixed-size-memory-pool.cpp
+ ${internal_src_dir}/common/const-string.cpp
${internal_src_dir}/event/actors/actor-impl.cpp
${internal_src_dir}/event/actors/actor-property-handler.cpp
${internal_src_dir}/event/actors/actor-relayouter.cpp
+ ${internal_src_dir}/event/actors/actor-siblings.cpp
${internal_src_dir}/event/actors/custom-actor-internal.cpp
${internal_src_dir}/event/actors/layer-impl.cpp
${internal_src_dir}/event/actors/layer-list.cpp
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <dali/public-api/common/dali-vector.h>
#include <dali/internal/common/buffer-index.h>
+#include <dali/internal/update/common/uniform-map.h>
+#include <dali/public-api/common/dali-vector.h>
namespace Dali
{
class UniformMap;
class UniformPropertyMapping;
-using CollectedUniformMap = Dali::Vector<const UniformPropertyMapping*>;
+using CollectedUniformMap = Dali::Vector<UniformPropertyMapping>;
/**
* This class maps uniform names to property value pointers.
const uint32_t attributeCount = vertexBuffer->GetAttributeCount();
for( uint32_t j = 0; j < attributeCount; ++j )
{
- const std::string& attributeName = vertexBuffer->GetAttributeName( j );
+ auto attributeName = vertexBuffer->GetAttributeName( j );
uint32_t index = program.RegisterCustomAttribute( attributeName );
GLint location = program.GetCustomAttributeLocation( index );
if( -1 == location )
{
- DALI_LOG_WARNING( "Attribute not found in the shader: %s\n", attributeName.c_str() );
+ DALI_LOG_WARNING( "Attribute not found in the shader: %s\n", attributeName.GetCString() );
}
attributeLocation.PushBack( location );
uint32_t mapIndex = 0;
for(; mapIndex < uniformMap.Count() ; ++mapIndex )
{
- mUniformIndexMap[mapIndex].propertyValue = uniformMap[mapIndex]->propertyPtr;
- mUniformIndexMap[mapIndex].uniformIndex = program.RegisterUniform( uniformMap[mapIndex]->uniformName );
+ mUniformIndexMap[mapIndex].propertyValue = uniformMap[mapIndex].propertyPtr;
+ mUniformIndexMap[mapIndex].uniformIndex = program.RegisterUniform(uniformMap[mapIndex].uniformName);
}
for( uint32_t nodeMapIndex = 0; nodeMapIndex < uniformMapNode.Count() ; ++nodeMapIndex )
{
- uint32_t uniformIndex = program.RegisterUniform( uniformMapNode[nodeMapIndex]->uniformName );
+ uint32_t uniformIndex = program.RegisterUniform(uniformMapNode[nodeMapIndex].uniformName);
bool found(false);
for( uint32_t i = 0; i<uniformMap.Count(); ++i )
{
if( mUniformIndexMap[i].uniformIndex == uniformIndex )
{
- mUniformIndexMap[i].propertyValue = uniformMapNode[nodeMapIndex]->propertyPtr;
+ mUniformIndexMap[i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
found = true;
break;
}
if( !found )
{
- mUniformIndexMap[mapIndex].propertyValue = uniformMapNode[nodeMapIndex]->propertyPtr;
+ mUniformIndexMap[mapIndex].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
mUniformIndexMap[mapIndex].uniformIndex = uniformIndex;
++mapIndex;
}
uint64_t hash = 0xc70f6907UL;
const SceneGraph::CollectedUniformMap& uniformMapNode = node->GetUniformMap( bufferIndex );
- for (const auto* uniformProperty : uniformMapNode)
+ for(const auto& uniformProperty : uniformMapNode)
{
- hash = uniformProperty->propertyPtr->Hash(bufferIndex, hash);
+ hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
}
const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMap();
const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetUniformMap( bufferIndex );
- for (const auto* uniformProperty : uniformMap)
+ for(const auto& uniformProperty : uniformMap)
{
- hash = uniformProperty->propertyPtr->Hash(bufferIndex, hash);
+ hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
}
if (mUniformsHash != hash)
#include <dali/internal/common/owner-pointer.h>
#include <dali/internal/render/renderers/render-sampler.h>
#include <dali/internal/render/gl-resources/gpu-buffer.h>
+#include <dali/internal/common/const-string.h>
namespace Dali
{
struct Component
{
- std::string name;
+ ConstString name;
uint32_t offset;
uint32_t size;
Property::Type type;
* @param[in] index The index of the attribute
* @return The name of the attribute
*/
- inline const std::string& GetAttributeName( uint32_t index ) const
+ inline ConstString GetAttributeName( uint32_t index ) const
{
DALI_ASSERT_DEBUG( mFormat && "Format should be set ");
return mFormat->components[index].name;
return GetCustomAttributeLocation( type );
}
-uint32_t Program::RegisterCustomAttribute( const std::string& name )
+uint32_t Program::RegisterCustomAttribute( ConstString name )
{
uint32_t index = 0;
// find the value from cache
if( location == ATTRIB_UNKNOWN )
{
- location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetAttribLocation( mProgramId, mAttributeLocations[ attributeIndex ].first.c_str() ) );
+ location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetAttribLocation( mProgramId, mAttributeLocations[ attributeIndex ].first.GetCString() ) );
mAttributeLocations[ attributeIndex ].second = location;
- LOG_GL( "GetAttributeLocation(program=%d,%s) = %d\n", mProgramId, mAttributeLocations[ attributeIndex ].first.c_str(), mAttributeLocations[ attributeIndex ].second );
+ LOG_GL( "GetAttributeLocation(program=%d,%s) = %d\n", mProgramId, mAttributeLocations[ attributeIndex ].first.GetCString(), mAttributeLocations[ attributeIndex ].second );
}
return location;
}
-uint32_t Program::RegisterUniform( const std::string& name )
+uint32_t Program::RegisterUniform( ConstString name )
{
uint32_t index = 0;
// find the value from cache
if( location == UNIFORM_NOT_QUERIED )
{
- location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetUniformLocation( mProgramId, mUniformLocations[ uniformIndex ].first.c_str() ) );
+ location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetUniformLocation( mProgramId, mUniformLocations[ uniformIndex ].first.GetCString() ) );
mUniformLocations[ uniformIndex ].second = location;
- LOG_GL( "GetUniformLocation(program=%d,%s) = %d\n", mProgramId, mUniformLocations[ uniformIndex ].first.c_str(), mUniformLocations[ uniformIndex ].second );
+ LOG_GL( "GetUniformLocation(program=%d,%s) = %d\n", mProgramId, mUniformLocations[ uniformIndex ].first.GetCString(), mUniformLocations[ uniformIndex ].second );
}
return location;
mAttributeLocations.reserve( ATTRIB_TYPE_LAST );
for( uint32_t i = 0; i < ATTRIB_TYPE_LAST; ++i )
{
- RegisterCustomAttribute( gStdAttribs[i] );
+ RegisterCustomAttribute( ConstString(gStdAttribs[i]) );
}
// reserve space for standard uniforms
// reset built in uniform names in cache
for( uint32_t i = 0; i < UNIFORM_TYPE_LAST; ++i )
{
- RegisterUniform( gStdUniforms[ i ] );
+ RegisterUniform( ConstString(gStdUniforms[ i ]) );
}
// reset values
#include <dali/public-api/object/ref-object.h>
#include <dali/integration-api/gl-abstraction.h>
#include <dali/internal/common/shader-data.h>
+#include <dali/internal/common/const-string.h>
namespace Dali
{
* @param [in] name attribute name
* @return the index of the attribute name in local cache
*/
- uint32_t RegisterCustomAttribute( const std::string& name );
+ uint32_t RegisterCustomAttribute( ConstString name );
/**
* Gets the location of a pre-registered attribute.
* @param [in] name uniform name
* @return the index of the uniform name in local cache
*/
- uint32_t RegisterUniform( const std::string& name );
+ uint32_t RegisterUniform( ConstString name );
/**
* Gets the location of a pre-registered uniform.
Internal::ShaderDataPtr mProgramData; ///< Shader program source and binary (when compiled & linked or loaded)
// location caches
- using NameLocationPair = std::pair<std::string, GLint>;
+ using NameLocationPair = std::pair<ConstString, GLint>;
using Locations = std::vector<NameLocationPair>;
Locations mAttributeLocations; ///< attribute location cache
const Vector2 playRange( mPlayRange * mDurationSeconds );
float elapsedSecondsClamped = Clamp( mElapsedSeconds, playRange.x, playRange.y );
- //Remove animators whose PropertyOwner has been destroyed
- mAnimators.Erase(std::remove_if(mAnimators.begin(),
- mAnimators.end(),
- [](auto animator) { return animator->Orphan(); }),
- mAnimators.end());
+ bool cleanup = false;
//Loop through all animators
for(auto& animator : mAnimators)
{
+ if(animator->Orphan())
+ {
+ cleanup = true;
+ continue;
+ }
+
bool applied(true);
if(animator->IsEnabled())
{
INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
}
}
+
+ if(cleanup)
+ {
+ //Remove animators whose PropertyOwner has been destroyed
+ mAnimators.Erase(std::remove_if(mAnimators.begin(),
+ mAnimators.end(),
+ [](auto& animator) { return animator->Orphan(); }),
+ mAnimators.end());
+ }
}
} // namespace SceneGraph
#include <dali/internal/event/common/property-input-impl.h>
#include <dali/internal/update/common/property-owner.h>
#include <dali/internal/update/animation/scene-graph-constraint-base.h>
+#include <dali/internal/common/const-string.h>
namespace Dali
{
new (slot) LocalType( &owner, &PropertyOwner::RemoveConstraint, &constraint );
}
-inline void AddUniformMapMessage( EventThreadServices& eventThreadServices, const PropertyOwner& owner, OwnerPointer< UniformPropertyMapping >& map )
+inline void AddUniformMapMessage(EventThreadServices& eventThreadServices, const PropertyOwner& owner, UniformPropertyMapping map)
{
- using LocalType = MessageValue1<PropertyOwner, OwnerPointer<UniformPropertyMapping> >;
+ using LocalType = MessageValue1<PropertyOwner, UniformPropertyMapping>;
// Reserve some memory inside the message queue
uint32_t* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
new (slot) LocalType( &owner, &PropertyOwner::AddUniformMapping, map );
}
-inline void RemoveUniformMapMessage( EventThreadServices& eventThreadServices, const PropertyOwner& owner, const std::string& uniformName )
+inline void RemoveUniformMapMessage( EventThreadServices& eventThreadServices, const PropertyOwner& owner, ConstString uniformName )
{
- using LocalType = MessageValue1<PropertyOwner, std::string>;
+ using LocalType = MessageValue1<PropertyOwner, ConstString>;
// Reserve some memory inside the message queue
uint32_t* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
// INTERNAL INCLUDES
#include <dali/public-api/common/dali-common.h>
#include <dali/internal/update/animation/scene-graph-constraint-base.h>
+#include <dali/internal/common/const-string.h>
namespace Dali
{
{
}
-void PropertyOwner::AddUniformMapping( OwnerPointer< UniformPropertyMapping >& map )
+void PropertyOwner::AddUniformMapping(const UniformPropertyMapping& map)
{
- mUniformMaps.Add( map.Release() );
+ mUniformMaps.Add(map);
}
-void PropertyOwner::RemoveUniformMapping( const std::string& uniformName )
+void PropertyOwner::RemoveUniformMapping( const ConstString& uniformName )
{
mUniformMaps.Remove( uniformName );
}
#include <dali/internal/update/common/scene-graph-buffers.h>
#include <dali/internal/update/common/uniform-map.h>
#include <dali/internal/update/animation/scene-graph-constraint-declarations.h>
+#include <dali/internal/common/const-string.h>
namespace Dali
/**
* @copydoc UniformMap::Add
*/
- virtual void AddUniformMapping( OwnerPointer< UniformPropertyMapping >& map );
+ virtual void AddUniformMapping(const UniformPropertyMapping& map);
/**
* @copydoc UniformMap::Remove
*/
- virtual void RemoveUniformMapping( const std::string& uniformName );
+ virtual void RemoveUniformMapping( const ConstString& uniformName );
/**
* Get the mappings table
* limitations under the License.
*/
+#include <algorithm>
+
// CLASS HEADER
#include <dali/internal/update/common/uniform-map.h>
{
namespace SceneGraph
{
-UniformMap::UniformMap() = default;
-
-UniformMap::~UniformMap()
-{
- // Nothing to do - let the owner container delete the maps
-}
void UniformMap::AddObserver( Observer& observer )
{
}
}
-void UniformMap::Add( UniformPropertyMapping* newMap )
+void UniformMap::Add(UniformPropertyMapping newMap)
{
- UniformPropertyMapping::Hash nameHash = CalculateHash( newMap->uniformName );
-
- bool found = false;
+ auto iter = std::find_if(mUniformMaps.Begin(),
+ mUniformMaps.End(),
+ [&](auto& element) { return element.uniformName == newMap.uniformName; });
- for( UniformMapIter iter = mUniformMaps.Begin() ;
- iter != mUniformMaps.End() ;
- ++iter )
+ if(iter != mUniformMaps.End())
{
- UniformPropertyMapping* map = *iter;
- if( map->uniformNameHash == nameHash )
- {
- if( map->uniformName == newMap->uniformName )
- {
- found = true;
- // Mapping already exists - update it.
- map->propertyPtr = newMap->propertyPtr;
- break;
- }
- }
+ // Mapping already exists - update it.
+ (*iter).propertyPtr = newMap.propertyPtr;
}
-
- if( found == false )
+ else
{
- // Take ownership of the new map
+ // add the new map.
mUniformMaps.PushBack(newMap);
}
MappingChanged();
}
-void UniformMap::Remove( const std::string& uniformName )
+void UniformMap::Remove( ConstString uniformName )
{
- UniformPropertyMapping::Hash nameHash = CalculateHash( uniformName );
-
- bool found=false;
+ auto iter = std::find_if(mUniformMaps.Begin(),
+ mUniformMaps.End(),
+ [&](auto& element) { return element.uniformName == uniformName; });
- for( UniformMapIter iter = mUniformMaps.Begin() ;
- iter != mUniformMaps.End() ;
- ++iter )
- {
- UniformPropertyMapping* map = *iter;
- if( map->uniformNameHash == nameHash )
- {
- if( map->uniformName == uniformName )
- {
- mUniformMaps.Erase( iter );
- found = true;
- break;
- }
- }
- }
-
- if( found )
+ if(iter != mUniformMaps.End())
{
+ mUniformMaps.Erase(iter);
MappingChanged();
}
}
-const PropertyInputImpl* UniformMap::Find( const std::string& uniformName )
+const PropertyInputImpl* UniformMap::Find(ConstString uniformName)
{
- UniformPropertyMapping::Hash nameHash = CalculateHash( uniformName );
+ auto iter = std::find_if(mUniformMaps.Begin(),
+ mUniformMaps.End(),
+ [&](auto& element) { return element.uniformName == uniformName; });
- for( UniformMapIter iter = mUniformMaps.Begin() ;
- iter != mUniformMaps.End() ;
- ++iter )
- {
- UniformPropertyMapping* map = *iter;
- if( map->uniformNameHash == nameHash )
- {
- if( map->uniformName == uniformName )
- {
- return map->propertyPtr;
- }
- }
- }
- return nullptr;
+ return (iter != mUniformMaps.End()) ? (*iter).propertyPtr : nullptr;
}
UniformMap::SizeType UniformMap::Count() const
const UniformPropertyMapping& UniformMap::operator[]( UniformMap::SizeType index ) const
{
- return *mUniformMaps[index];
+ return mUniformMaps[index];
}
} // SceneGraph
// INTERNAL INCLUDES
#include <dali/devel-api/common/hash.h>
#include <dali/devel-api/common/owner-container.h>
+#include <dali/internal/common/const-string.h>
namespace Dali
{
class UniformPropertyMapping
{
public:
- using Hash = unsigned long;
-
/**
* Constructor
*/
- UniformPropertyMapping(std::string theUniformName, const PropertyInputImpl* thePropertyPtr)
+ UniformPropertyMapping(ConstString theUniformName, const PropertyInputImpl* thePropertyPtr)
: propertyPtr(thePropertyPtr),
- uniformName(std::move(theUniformName)),
- uniformNameHash(Dali::CalculateHash(theUniformName))
- {
- }
-
- UniformPropertyMapping()
- : propertyPtr( nullptr ),
- uniformName( "" ),
- uniformNameHash( 0 )
+ uniformName(theUniformName)
{
}
+ UniformPropertyMapping() = default;
- const PropertyInputImpl* propertyPtr;
- std::string uniformName;
- Hash uniformNameHash;
+ const PropertyInputImpl* propertyPtr{nullptr};
+ ConstString uniformName;
};
/**
};
/**
- * Constructor
- */
- UniformMap();
-
- /**
- * Destructor
- */
- ~UniformMap();
-
- /**
* Add an observer that watches for changes in the mappings
*/
void AddObserver( Observer& observer );
/**
* Add a map to the mappings table.
*/
- void Add( UniformPropertyMapping* map );
+ void Add(UniformPropertyMapping map);
/**
* Remove a map from the mappings table
*/
- void Remove( const std::string& uniformName );
+ void Remove( ConstString uniformName );
/**
* Find a property given the uniform name.
* @return The address of the property if it's in the map, or NULL otherwise.
*/
- const PropertyInputImpl* Find( const std::string& uniformName );
+ const PropertyInputImpl* Find( ConstString uniformName );
/**
* Get the count of uniforms in the map
void MappingChanged();
private:
- using UniformMapContainer = OwnerContainer<UniformPropertyMapping*>;
+ using UniformMapContainer = Dali::Vector<UniformPropertyMapping>;
using UniformMapIter = UniformMapContainer::Iterator;
using Observers = Dali::Vector<Observer*>;
using ObserversIter = Observers::Iterator;
mIsRoot = isRoot;
}
-void Node::AddUniformMapping( OwnerPointer< UniformPropertyMapping >& map )
+void Node::AddUniformMapping(const UniformPropertyMapping& map)
{
PropertyOwner::AddUniformMapping( map );
mRegenerateUniformMap = 2;
}
-void Node::RemoveUniformMapping( const std::string& uniformName )
+void Node::RemoveUniformMapping( const ConstString& uniformName )
{
PropertyOwner::RemoveUniformMapping( uniformName );
mRegenerateUniformMap = 2;
for( UniformMap::SizeType i = 0, count=mUniformMaps.Count(); i<count; ++i )
{
- localMap.PushBack( &mUniformMaps[i] );
+ localMap.PushBack(mUniformMaps[i]);
}
}
else if( mRegenerateUniformMap == 1 )
/**
* @copydoc UniformMap::Add
*/
- void AddUniformMapping( OwnerPointer< UniformPropertyMapping >& map ) override;
+ void AddUniformMapping(const UniformPropertyMapping& map) override;
/**
* @copydoc UniformMap::Remove
*/
- void RemoveUniformMapping( const std::string& uniformName ) override;
+ void RemoveUniformMapping( const ConstString& uniformName ) override;
/**
* @copydoc Dali::Internal::SceneGraph::PropertyOwner::IsAnimationPossible
#include <dali/internal/render/renderers/render-geometry.h>
#include <dali/internal/render/shaders/program.h>
#include <dali/internal/render/shaders/scene-graph-shader.h>
+#include <dali/internal/common/blending-options.h>
namespace Dali
{
for( UniformMap::SizeType i = 0, count=uniformMap.Count(); i<count; ++i )
{
- UniformPropertyMapping::Hash nameHash = uniformMap[i].uniformNameHash;
bool found = false;
for( CollectedUniformMap::Iterator iter = localMap.Begin() ; iter != localMap.End() ; ++iter )
{
- const UniformPropertyMapping* map = (*iter);
- if( map->uniformNameHash == nameHash )
+ const UniformPropertyMapping& map = (*iter);
+ if(map.uniformName == uniformMap[i].uniformName)
{
- if( map->uniformName == uniformMap[i].uniformName )
- {
- found = true;
- break;
- }
+ found = true;
+ break;
}
}
if( !found )
{
- // it's a new mapping. Add raw ptr to temporary list
- newUniformMappings.PushBack( &uniformMap[i] );
+ newUniformMappings.PushBack(uniformMap[i]);
}
}
iter != end ;
++iter )
{
- const UniformPropertyMapping* map = (*iter);
+ const UniformPropertyMapping& map = (*iter);
localMap.PushBack( map );
}
}
if( mRegenerateUniformMap == REGENERATE_UNIFORM_MAP)
{
CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
- localMap.Resize(0);
+ localMap.Clear();
const UniformMap& rendererUniformMap = PropertyOwner::GetUniformMap();
+
+ auto size = rendererUniformMap.Count();
+
+ if(mShader)
+ {
+ size += mShader->GetUniformMap().Count();
+ }
+
+ localMap.Reserve(size);
+
AddMappings( localMap, rendererUniformMap );
if( mShader )
}
case BlendMode::AUTO:
{
+ if(BlendingOptions::IsAdvancedBlendEquationIncluded(mBlendBitmask))
+ {
+ opacityType = Renderer::TRANSLUCENT;
+ break;
+ }
+
bool shaderRequiresBlending( mShader->HintEnabled( Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT ) );
if( shaderRequiresBlending || ( mTextureSet && mTextureSet->HasAlpha() ) )
{
{
opacityType = Renderer::TRANSLUCENT;
}
+
break;
}
case BlendMode::OFF: // the renderer should never use blending
namespace Dali
{
-namespace
-{
-constexpr uint32_t BitMaskOfN(uint32_t bits)
-{
- return (1 << bits) - 1;
-}
-
-} // unnamed namespace
-
AlphaFunction::AlphaFunction()
-: mBezierControlPoints(Vector4::ZERO),
- mCustom(nullptr),
- mBuiltin(DEFAULT),
- mMode(BUILTIN_FUNCTION)
+: mMode(BUILTIN_FUNCTION),
+ mBuiltin(DEFAULT)
{
}
AlphaFunction::AlphaFunction(BuiltinFunction function)
-: mBezierControlPoints(Vector4::ZERO),
- mCustom(nullptr),
- mBuiltin(function),
- mMode(BUILTIN_FUNCTION)
+: mMode(BUILTIN_FUNCTION),
+ mBuiltin(function)
{
}
AlphaFunction::AlphaFunction(AlphaFunctionPrototype function)
-: mBezierControlPoints(Vector4::ZERO),
- mCustom(function),
+: mMode(CUSTOM_FUNCTION),
mBuiltin(DEFAULT),
- mMode(CUSTOM_FUNCTION)
+ mCustom(function)
{
}
AlphaFunction::AlphaFunction(const Vector2& controlPoint0, const Vector2& controlPoint1)
-: mBezierControlPoints(
+: mMode(BEZIER),
+ mBuiltin(DEFAULT),
+ mBezierControlPoints(
Vector4(Clamp(controlPoint0.x, 0.0f, 1.0f),
controlPoint0.y,
Clamp(controlPoint1.x, 0.0f, 1.0f),
- controlPoint1.y)),
- mCustom(nullptr),
- mBuiltin(DEFAULT),
- mMode(BEZIER)
+ controlPoint1.y))
{
}
Vector4 AlphaFunction::GetBezierControlPoints() const
{
- return mBezierControlPoints;
+ return (mMode == BEZIER) ? mBezierControlPoints : Vector4::ZERO;
}
AlphaFunctionPrototype AlphaFunction::GetCustomFunction() const
{
- return mCustom;
+ return (mMode == CUSTOM_FUNCTION) ? mCustom : nullptr;
}
AlphaFunction::BuiltinFunction AlphaFunction::GetBuiltinFunction() const
{
- return static_cast<AlphaFunction::BuiltinFunction>(mBuiltin & BitMaskOfN(Log<COUNT>::value + 1));
+ return mBuiltin;
}
AlphaFunction::Mode AlphaFunction::GetMode() const
{
- return static_cast<AlphaFunction::Mode>(mMode & BitMaskOfN(2));
+ return mMode;
}
} // namespace Dali
*
*/
+// EXTERNAL INCLUDES
+#include <cstdint> // uint8_t
+
// INTERNAL INCLUDES
#include <dali/public-api/common/constants.h>
#include <dali/public-api/common/dali-common.h>
* @brief Enumeration for built-in alpha functions.
* @SINCE_1_0.0
*/
- enum BuiltinFunction
+ enum BuiltinFunction : uint8_t
{
DEFAULT, ///< Linear @SINCE_1_0.0
LINEAR, ///< No transformation @SINCE_1_0.0
* @brief Enumeration for all possible functioning modes for the alpha function.
* @SINCE_1_0.0
*/
- enum Mode
+ enum Mode : uint8_t
{
BUILTIN_FUNCTION, ///< The user has specified a built-in function @SINCE_1_0.0
CUSTOM_FUNCTION, ///< The user has provided a custom function @SINCE_1_0.0
Mode GetMode() const;
private:
- Vector4 mBezierControlPoints; //< Control points for the bezier alpha function
- AlphaFunctionPrototype mCustom; //< Pointer to an alpha function
- BuiltinFunction mBuiltin : Log<COUNT>::value + 1; //< Enum indicating the built-in alpha function
- Mode mMode : 2; //< Enum indicating the functioning mode of the AlphaFunction
+ Mode mMode; //< Enum indicating the functioning mode of the AlphaFunction
+ BuiltinFunction mBuiltin; //< Enum indicating the built-in alpha function
+
+ union
+ {
+ Vector4 mBezierControlPoints; //< Control points for the bezier alpha function
+ AlphaFunctionPrototype mCustom; //< Pointer to an alpha function
+ };
};
/**
{
const uint32_t CORE_MAJOR_VERSION = 2;
const uint32_t CORE_MINOR_VERSION = 0;
-const uint32_t CORE_MICRO_VERSION = 3;
+const uint32_t CORE_MICRO_VERSION = 4;
const char* const CORE_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
std::string Handle::GetPropertyName(Property::Index index) const
{
- return GetImplementation(*this).GetPropertyName(index);
+ return std::string(GetImplementation(*this).GetPropertyName(index));
}
Property::Index Handle::GetPropertyIndex(Property::Key key) const
GetImplementation(*this).SetProperty(index, std::move(propertyValue));
}
-Property::Index Handle::RegisterProperty(std::string name, Property::Value propertyValue)
+Property::Index Handle::RegisterProperty(std::string_view name, Property::Value propertyValue)
{
- return GetImplementation(*this).RegisterProperty(std::move(name), std::move(propertyValue));
+ return GetImplementation(*this).RegisterProperty(name, std::move(propertyValue));
}
-Property::Index Handle::RegisterProperty(Property::Index key, std::string name, Property::Value propertyValue)
+Property::Index Handle::RegisterProperty(Property::Index key, std::string_view name, Property::Value propertyValue)
{
- return GetImplementation(*this).RegisterProperty(std::move(name), key, std::move(propertyValue));
+ return GetImplementation(*this).RegisterProperty(name, key, std::move(propertyValue));
}
-Property::Index Handle::RegisterProperty(std::string name, Property::Value propertyValue, Property::AccessMode accessMode)
+Property::Index Handle::RegisterProperty(std::string_view name, Property::Value propertyValue, Property::AccessMode accessMode)
{
- return GetImplementation(*this).RegisterProperty(std::move(name), std::move(propertyValue), accessMode);
+ return GetImplementation(*this).RegisterProperty(name, std::move(propertyValue), accessMode);
}
Property::Value Handle::GetProperty(Property::Index index) const
* - Property::ROTATION
* @note If a property with the desired name already exists, then the value given is just set.
*/
- Property::Index RegisterProperty(std::string name, Property::Value propertyValue);
+ Property::Index RegisterProperty(std::string_view name, Property::Value propertyValue);
/**
* @brief Register a new animatable property with an integer key.
* - Property::ROTATION
* @note If a property with the desired name already exists, then the value given is just set.
*/
- Property::Index RegisterProperty(Property::Index key,
- std::string name,
- Property::Value propertyValue);
+ Property::Index RegisterProperty(Property::Index key,
+ std::string_view name,
+ Property::Value propertyValue);
/**
* @brief Registers a new property.
* - Property::ROTATION
* @note If a property with the desired name already exists, then the value given is just set.
*/
- Property::Index RegisterProperty(std::string name, Property::Value propertyValue, Property::AccessMode accessMode);
+ Property::Index RegisterProperty(std::string_view name, Property::Value propertyValue, Property::AccessMode accessMode);
/**
* @brief Retrieves a property value.
void RefObject::Reference()
{
- // clang-format off
- // The inline assembly below was tested on an ARMv8 64 bit platform on
- // 2015-02-06 and found to run in 11.8 nanoseconds, whereas
- // __sync_add_and_fetch( address, 1 ) required 18.8 nanoseconds.
- // Including the assembly here produced one fewer assembly instruction than if
- // it was wrapped in a function and inlined here by the compiler.
-#if defined __aarch64__
-
- asm volatile(
- "1:\tldxr w1, %[address] \n\t"
- "add w1, w1, %[one] \n\t"
- "stxr w2, w1, %[address] \n\t"
- "cbnz w2, 1b \n\t"
- // Outputs:
- : // Q = A memory address with no offset
- // ( https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints )
- [address] "+Q" (mCount)
- // Inputs:
- : [one] "Ir" (1)
- // Clobbers: (explicitly clobber w1 register to hold the loaded value and
- // register w2 to hold success/fail):
- : "w1", "w2"
- );
-
- // 32 bit ARMv7 version of above:
- // Better than the code emitted by GCC for __sync_add_and_fetch(), as that
- // includes two dmb memory barrier instructions: one before and one after the
- // loop.
-#elif defined __arm__
-
- asm volatile(
- "1:\tldrex r1, %[address] \n\t"
- "add r1, r1, %[one] \n\t"
- "strex r2, r1, %[address] \n\t"
- "teq r2, %[zero] \n\t"
- "bne 1b \n\t"
- // Outputs:
- : [address] "+Q" (mCount)
- // Inputs:
- : [zero] "Ir" (0),
- [one] "Ir" (1)
- // Clobbers: (modified registers):
- : "r1", "r2"
- );
-
-#else
-
- // gcc > 4.1 builtin atomic add and fetch:
- __sync_add_and_fetch( &mCount, 1 );
-
-#endif
- // clang-format on
+ ++mCount;
}
void RefObject::Unreference()
{
- // clang-format off
-
- // The output register:
- int32_t newValue;
-
-#if defined __aarch64__
-
- asm volatile(
- "1:\tldxr %w[newValue], %[address] \n\t"
- "sub %w[newValue], %w[newValue], %[one] \n\t"
- "stxr w2, %w[newValue], %[address] \n\t"
- "cbnz w2, 1b \n\t"
- // Outputs:
- : [newValue] "=&r" (newValue),
- // Q = A memory address with no offset
- // ( https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints )
- [address] "+Q" (mCount)
- // Inputs:
- : [one] "Ir" (1)
- // Clobbered: I.e., stuff that is modified.
- : "w2"
- );
-
-#elif defined __arm__
-
- asm volatile(
- "1:\tldrex %[newValue], %[address] \n\t"
- "sub %[newValue], %[newValue], %[one] \n\t"
- "strex r2, %[newValue], %[address] \n\t"
- "teq r2, %[zero] \n\t"
- "bne 1b \n\t"
- // Outputs:
- : [newValue] "=&r" (newValue),
- [address] "+Q" (mCount)
- // Inputs:
- : [zero] "Ir" (0),
- [one] "Ir" (1)
- // Clobbered:
- : "r2"
- );
-
-#else
-
- // gcc > 4.1 builtin atomic subtract and fetch (--mCount; return mCount)
- newValue = __sync_sub_and_fetch( &mCount, 1 );
-
-#endif
-
- if( newValue == 0 )
+ if( (--mCount) == 0 )
{
delete this;
}
- // clang-format on
}
uint32_t RefObject::ReferenceCount()
// EXTERNAL INCLUDES
#include <cstdint> // uint32_t
+#include <atomic>
// INTERNAL INCLUDES
#include <dali/public-api/common/dali-common.h>
RefObject& operator=(const RefObject& rhs);
private:
- volatile uint32_t mCount; ///< Reference count
+ std::atomic_uint32_t mCount {0u}; ///< Reference count
};
/**
GetImplementation(*this).GetPropertyIndices(indices);
}
-const std::string& TypeInfo::GetPropertyName(Property::Index index) const
+std::string_view TypeInfo::GetPropertyName(Property::Index index) const
{
return GetImplementation(*this).GetRegisteredPropertyName(index);
}
Property::Index TypeInfo::GetChildPropertyIndex(const std::string& name) const
{
- return GetImplementation(*this).GetChildPropertyIndex(name);
+ return GetImplementation(*this).GetChildPropertyIndex(Internal::ConstString(name));
}
-const std::string& TypeInfo::GetChildPropertyName(Property::Index index) const
+std::string_view TypeInfo::GetChildPropertyName(Property::Index index) const
{
return GetImplementation(*this).GetChildPropertyName(index);
}
* @exception DaliException If index is not valid.
* @note this method only works for custom registered properties
*/
- const std::string& GetPropertyName(Property::Index index) const;
+ std::string_view GetPropertyName(Property::Index index) const;
/**
* @brief Given a child property name, retrieve the property index associated with it,
* @param[in] index The property index
* @return The name of the property at the given index, or empty string if it does not exist
*/
- const std::string& GetChildPropertyName(Property::Index index) const;
+ std::string_view GetChildPropertyName(Property::Index index) const;
/**
* @brief Given a child property index, retrieve the property name associated with it.
Name: dali2
Summary: DALi 3D Engine
-Version: 2.0.3
+Version: 2.0.4
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT