--- /dev/null
+{\r
+ "scene" : 0,\r
+ "scenes" : [\r
+ {\r
+ "nodes" : [ 0 ]\r
+ }\r
+ ],\r
+\r
+ "nodes" : [\r
+ {\r
+ "mesh" : 0,\r
+ "rotation" : [ 0.0, 0.0, 0.0, 1.0 ],\r
+ "scale": [\r
+ 100.0,\r
+ 100.0,\r
+ 100.0\r
+ ],\r
+ "name": "RootNode"\r
+ }\r
+ ],\r
+\r
+ "meshes" : [\r
+ {\r
+ "primitives" : [ {\r
+ "attributes" : {\r
+ "POSITION" : 1\r
+ },\r
+ "indices" : 0,\r
+ "material": 0\r
+ } ]\r
+ }\r
+ ],\r
+\r
+ "animations": [\r
+ {\r
+ "samplers" : [\r
+ {\r
+ "input" : 2,\r
+ "interpolation" : "LINEAR",\r
+ "output" : 3\r
+ }\r
+ ],\r
+ "channels" : [ {\r
+ "sampler" : 0,\r
+ "target" : {\r
+ "node" : 0,\r
+ "path" : "rotation"\r
+ }\r
+ } ]\r
+ }\r
+ ],\r
+\r
+ "buffers" : [\r
+ {\r
+ "uri" : "simpleTriangle.bin",\r
+ "byteLength" : 44\r
+ },\r
+ {\r
+ "uri" : "animation.bin",\r
+ "byteLength" : 100\r
+ }\r
+ ],\r
+\r
+ "bufferViews" : [\r
+ {\r
+ "buffer" : 0,\r
+ "byteOffset" : 0,\r
+ "byteLength" : 6,\r
+ "target" : 34963\r
+ },\r
+ {\r
+ "buffer" : 0,\r
+ "byteOffset" : 8,\r
+ "byteLength" : 36,\r
+ "target" : 34962\r
+ },\r
+ {\r
+ "buffer" : 1,\r
+ "byteOffset" : 0,\r
+ "byteLength" : 100\r
+ }\r
+ ],\r
+\r
+ "accessors" : [\r
+ {\r
+ "bufferView" : 0,\r
+ "byteOffset" : 0,\r
+ "componentType" : 5123,\r
+ "count" : 3,\r
+ "type" : "SCALAR",\r
+ "max" : [ 2 ],\r
+ "min" : [ 0 ]\r
+ },\r
+ {\r
+ "bufferView" : 1,\r
+ "byteOffset" : 0,\r
+ "componentType" : 5126,\r
+ "count" : 3,\r
+ "type" : "VEC3",\r
+ "max" : [ 1.0, 1.0, 0.0 ],\r
+ "min" : [ 0.0, 0.0, 0.0 ]\r
+ },\r
+ {\r
+ "bufferView" : 2,\r
+ "byteOffset" : 0,\r
+ "componentType" : 5126,\r
+ "count" : 5,\r
+ "type" : "SCALAR",\r
+ "max" : [ 1.0 ],\r
+ "min" : [ 0.0 ]\r
+ },\r
+ {\r
+ "bufferView" : 2,\r
+ "byteOffset" : 20,\r
+ "componentType" : 5126,\r
+ "count" : 5,\r
+ "type" : "VEC4",\r
+ "max" : [ 0.0, 0.0, 1.0, 1.0 ],\r
+ "min" : [ 0.0, 0.0, 0.0, -0.707 ]\r
+ }\r
+ ],\r
+\r
+ "asset" : {\r
+ "generator": "glTF Tools for M-Renderer",\r
+ "version" : "2.0"\r
+ },\r
+\r
+ "materials": [\r
+ {\r
+ "pbrMetallicRoughness":\r
+ {\r
+ "baseColorTexture":\r
+ {\r
+ "index": 0,\r
+ "texCoord": 0\r
+ },\r
+ "metallicFactor": 0,\r
+ "baseColorFactor":\r
+ [\r
+ 1,\r
+ 1,\r
+ 1,\r
+ 1\r
+ ],\r
+ "roughnessFactor": 1\r
+ },\r
+ "emissiveFactor":\r
+ [\r
+ 0,\r
+ 0,\r
+ 0\r
+ ],\r
+ "alphaMode": "OPAQUE",\r
+ "doubleSided": false\r
+ }\r
+ ],\r
+\r
+ "textures": [\r
+ {\r
+ "sampler": 0,\r
+ "source": 0\r
+ }\r
+ ],\r
+\r
+ "images": [\r
+ {\r
+ "uri": "AnimatedCube_BaseColor.png"\r
+ }\r
+ ],\r
+\r
+ "samplers": [\r
+ {\r
+ "magFilter": 9729,\r
+ "minFilter": 9986,\r
+ "wrapS": 10497,\r
+ "wrapT": 10497\r
+ }\r
+ ]\r
+}\r
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
// Enable debug log for test coverage
#define DEBUG_ENABLED 1
+#include <dali-test-suite-utils.h>
+#include <string_view>
+#include "dali-scene-loader/public-api/gltf2-loader.h"
+#include "dali-scene-loader/public-api/load-result.h"
#include "dali-scene-loader/public-api/resource-bundle.h"
#include "dali-scene-loader/public-api/scene-definition.h"
-#include "dali-scene-loader/public-api/load-result.h"
-#include "dali-scene-loader/public-api/gltf2-loader.h"
#include "dali-scene-loader/public-api/shader-definition-factory.h"
-#include <dali-test-suite-utils.h>
-#include <string_view>
using namespace Dali;
using namespace Dali::SceneLoader;
#define DALI_TEST_THROW(expression, exception, predicate) \
- {\
- bool daliTestThrowSuccess__ = false;\
- try\
- {\
- do { expression; } while(0);\
- printf("No exception was thrown.\n");\
- }\
- catch (std::decay<exception>::type& ex)\
- {\
- daliTestThrowSuccess__ = predicate(ex);\
- }\
- catch (...)\
- {\
- printf("Wrong type of exception thrown.\n");\
- }\
- DALI_TEST_CHECK(daliTestThrowSuccess__);\
+ { \
+ bool daliTestThrowSuccess__ = false; \
+ try \
+ { \
+ do \
+ { \
+ expression; \
+ } while(0); \
+ printf("No exception was thrown.\n"); \
+ } \
+ catch(std::decay<exception>::type & ex) \
+ { \
+ daliTestThrowSuccess__ = predicate(ex); \
+ } \
+ catch(...) \
+ { \
+ printf("Wrong type of exception thrown.\n"); \
+ } \
+ DALI_TEST_CHECK(daliTestThrowSuccess__); \
}
namespace
{
struct Context
{
- ResourceBundle resources;
+ ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) {
+ return TEST_RESOURCE_DIR "/";
+ };
+
+ ResourceBundle resources;
SceneDefinition scene;
- std::vector<AnimationDefinition> animations;
+ std::vector<AnimationDefinition> animations;
std::vector<AnimationGroupDefinition> animationGroups;
- std::vector<CameraParameters> cameras;
- std::vector<LightParameters> lights;
+ std::vector<CameraParameters> cameras;
+ std::vector<LightParameters> lights;
- LoadResult loadResult {
+ LoadResult loadResult{
resources,
scene,
animations,
animationGroups,
cameras,
- lights
- };
+ lights};
};
struct ExceptionMessageStartsWith
bool operator()(const std::runtime_error& e)
{
const bool success = (0 == strncmp(e.what(), expected.data(), expected.size()));
- if (!success)
+ if(!success)
{
printf("Expected: %s, got: %s.\n", expected.data(), e.what());
}
}
};
-}
+} // namespace
int UtcDaliGltfLoaderFailedToLoad(void)
{
sdf.SetResources(ctx.resources);
DALI_TEST_THROW(LoadGltfScene("non-existent.gltf", sdf, ctx.loadResult),
- std::runtime_error,
- ExceptionMessageStartsWith{"Failed to load"});
+ std::runtime_error,
+ ExceptionMessageStartsWith{"Failed to load"});
DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
sdf.SetResources(ctx.resources);
DALI_TEST_THROW(LoadGltfScene(TEST_RESOURCE_DIR "/invalid.gltf", sdf, ctx.loadResult),
- std::runtime_error,
- ExceptionMessageStartsWith{"Failed to parse"});
+ std::runtime_error,
+ ExceptionMessageStartsWith{"Failed to parse"});
DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
auto& materials = ctx.resources.mMaterials;
DALI_TEST_EQUAL(2u, materials.size());
- const MaterialDefinition materialGroundTruth[] {
- {
- MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
- MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS |
- (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
- 0,
- Vector4(1.f, .766f, .336f, 1.f),
- 1.f,
- 0.f,
- {
- { MaterialDefinition::ALBEDO,
- { "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
- { MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
- { "AnimatedCube_MetallicRoughness.png",
- SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT) } },
- { MaterialDefinition::NORMAL,
- { "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
- }
- },
- {
- MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
- MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
- 0,
- Vector4(1.f, .766f, .336f, 1.f),
- 1.f,
- 0.f,
- {
- { MaterialDefinition::ALBEDO,
- { "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
- { MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
- { "AnimatedCube_MetallicRoughness.png",
- SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT) } },
- { MaterialDefinition::NORMAL,
- { "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
- }
- },
+ const MaterialDefinition materialGroundTruth[]{
+ {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+ MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS |
+ (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
+ 0,
+ Vector4(1.f, .766f, .336f, 1.f),
+ 1.f,
+ 0.f,
+ {
+ {MaterialDefinition::ALBEDO,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ {MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
+ {"AnimatedCube_MetallicRoughness.png",
+ SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT)}},
+ {MaterialDefinition::NORMAL,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ }},
+ {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+ MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
+ 0,
+ Vector4(1.f, .766f, .336f, 1.f),
+ 1.f,
+ 0.f,
+ {
+ {MaterialDefinition::ALBEDO,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ {MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
+ {"AnimatedCube_MetallicRoughness.png",
+ SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT)}},
+ {MaterialDefinition::NORMAL,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ }},
};
auto iMaterial = materials.begin();
- for (auto& m : materialGroundTruth)
+ for(auto& m : materialGroundTruth)
{
printf("material %ld\n", iMaterial - materials.begin());
auto& md = iMaterial->first;
DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
auto iTexture = md.mTextureStages.begin();
- for (auto& ts: m.mTextureStages)
+ for(auto& ts : m.mTextureStages)
{
printf("texture %ld\n", iTexture - md.mTextureStages.begin());
DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
auto& meshes = ctx.resources.mMeshes;
DALI_TEST_EQUAL(2u, meshes.size());
- using Blob = MeshDefinition::Blob;
+ using Blob = MeshDefinition::Blob;
using Accessor = MeshDefinition::Accessor;
- const MeshDefinition meshGroundTruth[] {
+ const MeshDefinition meshGroundTruth[]{
{
0,
Geometry::TRIANGLES,
"AnimatedCube.bin",
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
},
{
0,
Geometry::TRIANGLES,
"AnimatedCube.bin",
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
- Accessor{ Blob{ 0, 0 }, {} },
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
+ Accessor{Blob{0, 0}, {}},
},
};
auto iMesh = meshes.begin();
- for (auto& m : meshGroundTruth)
+ for(auto& m : meshGroundTruth)
{
printf("mesh %ld\n", iMesh - meshes.begin());
auto& md = iMesh->first;
DALI_TEST_EQUAL(md.mFlags, m.mFlags);
DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
- for (auto mp: {
- &MeshDefinition::mIndices,
- &MeshDefinition::mPositions,
- &MeshDefinition::mNormals,
- &MeshDefinition::mTexCoords,
- &MeshDefinition::mTangents,
- &MeshDefinition::mJoints0,
- &MeshDefinition::mWeights0
- })
+ for(auto mp : {
+ &MeshDefinition::mIndices,
+ &MeshDefinition::mPositions,
+ &MeshDefinition::mNormals,
+ &MeshDefinition::mTexCoords,
+ &MeshDefinition::mTangents,
+ &MeshDefinition::mJoints0,
+ &MeshDefinition::mWeights0})
{
DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
TestApplication app;
const std::string resourcePath = TEST_RESOURCE_DIR "/";
- auto pathProvider = [resourcePath](ResourceType::Value) {
+ auto pathProvider = [resourcePath](ResourceType::Value) {
return resourcePath;
};
Customization::Choices choices;
- for (auto modelName : {
- "2CylinderEngine",
- "AnimatedMorphCube",
- "AnimatedMorphSphere",
- "AnimatedTriangle",
- "BoxAnimated",
- "CesiumMan",
- "CesiumMilkTruck",
- "EnvironmentTest",
- "MetalRoughSpheres",
- "MorphPrimitivesTest",
- "SimpleSparseAccessor",
- })
+ for(auto modelName : {
+ "2CylinderEngine",
+ "AnimatedMorphCube",
+ "AnimatedMorphSphere",
+ "AnimatedTriangle",
+ "BoxAnimated",
+ "CesiumMan",
+ "CesiumMilkTruck",
+ "EnvironmentTest",
+ "MetalRoughSpheres",
+ "MorphPrimitivesTest",
+ "MRendererTest",
+ "SimpleSparseAccessor",
+ })
{
Context ctx;
DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
auto& scene = ctx.scene;
- for (auto iRoot : scene.GetRoots())
+ for(auto iRoot : scene.GetRoots())
{
- struct Visitor: NodeDefinition::IVisitor
+ struct Visitor : NodeDefinition::IVisitor
{
- struct ResourceReceiver: IResourceReceiver
+ struct ResourceReceiver : IResourceReceiver
{
std::vector<bool> mCounts;
void Register(ResourceType::Value type, Index id) override
{
- if (type == ResourceType::Mesh)
+ if(type == ResourceType::Mesh)
{
mCounts[id] = true;
}
void Start(NodeDefinition& n) override
{
- if (n.mRenderable)
+ if(n.mRenderable)
{
n.mRenderable->RegisterResources(receiver);
}
}
void Finish(NodeDefinition& n) override
- {}
+ {
+ }
} visitor;
visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
scene.Visit(iRoot, choices, visitor);
- for (uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
+ for(uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
{
- if (visitor.receiver.mCounts[i0])
+ if(visitor.receiver.mCounts[i0])
{
auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath);
DALI_TEST_CHECK(!raw.mAttribs.empty());
END_TEST;
}
+
+int UtcDaliGltfLoaderMRendererTest(void)
+{
+ Context ctx;
+
+ ShaderDefinitionFactory sdf;
+ sdf.SetResources(ctx.resources);
+ auto& resources = ctx.resources;
+ resources.mEnvironmentMaps.push_back({});
+
+ LoadGltfScene(TEST_RESOURCE_DIR "/MRendererTest.gltf", sdf, ctx.loadResult);
+
+ auto& scene = ctx.scene;
+ auto& roots = scene.GetRoots();
+ DALI_TEST_EQUAL(roots.size(), 1u);
+ DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "RootNode");
+ DALI_TEST_EQUAL(scene.GetNode(roots[0])->mScale, Vector3(1.0f, 1.0f, 1.0f));
+
+ DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
+
+ ViewProjection viewProjection;
+ Transforms xforms{
+ MatrixStack{},
+ viewProjection};
+ NodeDefinition::CreateParams nodeParams{
+ resources,
+ xforms,
+ };
+
+ Customization::Choices choices;
+
+ TestApplication app;
+
+ Actor root = Actor::New();
+ SetActorCentered(root);
+ for(auto iRoot : roots)
+ {
+ auto resourceRefs = resources.CreateRefCounter();
+ scene.CountResourceRefs(iRoot, choices, resourceRefs);
+ resources.CountEnvironmentReferences(resourceRefs);
+ resources.LoadResources(resourceRefs, ctx.pathProvider);
+ if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+ {
+ scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+ scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+ scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+ root.Add(actor);
+ }
+ }
+
+ DALI_TEST_EQUAL(root.GetChildCount(), 1u);
+ DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
+ DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
+
+ END_TEST;
+}
../dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp
../dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.cpp
../dali-toolkit/dali-toolkit-test-utils/toolkit-vector-image-renderer.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/toolkit-web-engine.cpp
../dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp
../dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder.cpp
../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/controls/popup/popup.h>
#include <dali-toolkit/devel-api/controls/table-view/table-view.h>
+#include <dali-toolkit/devel-api/controls/web-view/web-view.h>
#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/common/stage.h>
#include <cstdlib>
Dali::Accessibility::TestEnableSC( false );
END_TEST;
}
+
+int UtcDaliWebViewAccessible(void)
+{
+ ToolkitTestApplication application;
+
+ auto webView = Dali::Toolkit::WebView::New();
+ auto webViewAccessible = Dali::Accessibility::Accessible::Get(webView);
+
+ DALI_TEST_CHECK(webViewAccessible);
+
+ auto children = webViewAccessible->GetChildren();
+
+ DALI_TEST_CHECK(children.empty());
+
+ Dali::Accessibility::TestEnableSC(true);
+
+ children = webViewAccessible->GetChildren();
+
+ DALI_TEST_EQUALS(children.size(), 1u, TEST_LOCATION);
+
+ auto address = children[0]->GetAddress();
+
+ DALI_TEST_CHECK(address);
+ DALI_TEST_NOT_EQUALS(address.GetBus(), webViewAccessible->GetAddress().GetBus(), 0.0f, TEST_LOCATION);
+
+ Dali::Accessibility::TestEnableSC(false);
+
+ children = webViewAccessible->GetChildren();
+
+ DALI_TEST_CHECK(children.empty());
+
+ END_TEST;
+}
END_TEST;
}
+int UtcTextureManagerUseInvalidMaskAndMaskLoadedFirst(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcTextureManagerUseInvalidMask when normal image loaded first, and mask image loaded first");
+ tet_infoline("Try to check PostLoad works well");
+
+ TextureManager textureManager; // Create new texture manager
+
+ TestObserver observer;
+ std::string filename(TEST_IMAGE_FILE_NAME);
+ std::string maskname("invalid.png");
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ maskInfo.reset(new TextureManager::MaskingData());
+ maskInfo->mAlphaMaskUrl = maskname;
+ maskInfo->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
+ maskInfo->mCropToMask = true;
+ maskInfo->mContentScaleFactor = 1.0f;
+
+ auto textureId(TextureManager::INVALID_TEXTURE_ID);
+ Vector4 atlasRect(0.f, 0.f, 1.f, 1.f);
+ Dali::ImageDimensions atlasRectSize(0, 0);
+ bool synchronousLoading(false);
+ bool atlasingStatus(false);
+ bool loadingStatus(false);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ ImageAtlasManagerPtr atlasManager = nullptr;
+ Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+ textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ synchronousLoading,
+ textureId,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ loadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &observer,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer.mLoaded, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcTextureManagerUseInvalidMaskAndMaskLoadedLater(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcTextureManagerUseInvalidMask when normal image loaded first, and mask image loaded later");
+ tet_infoline("Try to check CheckForWaitingTexture called");
+
+ TextureManager textureManager; // Create new texture manager
+
+ TestObserver observer;
+ std::string filename(TEST_IMAGE_FILE_NAME);
+ std::string maskname("invalid.png");
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ maskInfo.reset(new TextureManager::MaskingData());
+ maskInfo->mAlphaMaskUrl = maskname;
+ maskInfo->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
+ maskInfo->mCropToMask = true;
+ maskInfo->mContentScaleFactor = 1.0f;
+
+ auto textureId(TextureManager::INVALID_TEXTURE_ID);
+ Vector4 atlasRect(0.f, 0.f, 1.f, 1.f);
+ Dali::ImageDimensions atlasRectSize(0, 0);
+ bool synchronousLoading(false);
+ bool atlasingStatus(false);
+ bool loadingStatus(false);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ ImageAtlasManagerPtr atlasManager = nullptr;
+ Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+ textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ synchronousLoading,
+ textureId,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ loadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &observer,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ // CAPTION : HARD-CODING for coverage. If you are a good boy, Do not follow this code.
+ {
+ Dali::Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ true, ///< synchronousLoading
+ nullptr,
+ true, ///< orientationCorrection
+ preMultiply);
+
+ textureManager.AsyncLoadComplete(textureId, pixelBuffer);
+ textureManager.AsyncLoadComplete(maskInfo->mAlphaMaskId, Dali::Devel::PixelBuffer());
+ textureManager.Remove(maskInfo->mAlphaMaskId, nullptr);
+ textureManager.Remove(textureId, &observer);
+ }
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer.mLoaded, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcTextureManagerSynchronousLoadingFail(void)
{
ToolkitTestApplication application;
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
#include <dali-toolkit/internal/visuals/color/color-visual.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
#include <dummy-visual.h>
#include <../dali-toolkit/dali-toolkit-test-utils/dummy-control.h>
#include <dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h>
END_TEST;
}
+int UtcDaliVisualUpdateBrokenImageRenderer(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UpdateBrokenImageRenderer Test" );
+
+ Toolkit::Internal::VisualFactoryCache* factoryCache = new Toolkit::Internal::VisualFactoryCache(false);
+
+ std::string defaultBrokenImageUrl = "not-9patch.png";
+
+ // Set default broken image
+ factoryCache->SetBrokenImageUrl(defaultBrokenImageUrl, std::vector<std::string>());
+
+ //Created dummy renderer
+ Geometry geometry = factoryCache->GetGeometry(Toolkit::Internal::VisualFactoryCache::QUAD_GEOMETRY);
+ Shader shader = Shader::New("foo","bar");
+ Renderer renderer = Renderer::New(geometry, shader);
+
+ DALI_TEST_CHECK(renderer);
+
+ // renderer doesn't changed.
+ factoryCache->UpdateBrokenImageRenderer(renderer, Vector2::ZERO, true);
+ Shader testShader1 = renderer.GetShader();
+
+ // Get default image renderer.
+ factoryCache->UpdateBrokenImageRenderer(renderer, Vector2::ZERO, false);
+ Shader testShader2 = renderer.GetShader();
+
+ // Get default image renderer but nine patch.
+ // Note : This API behavior can be changed. (DALi don't consider about default BrokenImageUrl is failed.
+ defaultBrokenImageUrl = "yes-9patch.9.png";
+ factoryCache->SetBrokenImageUrl(defaultBrokenImageUrl, std::vector<std::string>());
+ factoryCache->UpdateBrokenImageRenderer(renderer, Vector2::ZERO, false);
+ Shader testShader3 = renderer.GetShader();
+
+ DALI_TEST_CHECK(testShader1 != factoryCache->GetShader(Toolkit::Internal::VisualFactoryCache::IMAGE_SHADER));
+ DALI_TEST_CHECK(testShader1 != factoryCache->GetShader(Toolkit::Internal::VisualFactoryCache::NINE_PATCH_SHADER));
+ DALI_TEST_CHECK(testShader2 == factoryCache->GetShader(Toolkit::Internal::VisualFactoryCache::IMAGE_SHADER));
+ DALI_TEST_CHECK(testShader3 == factoryCache->GetShader(Toolkit::Internal::VisualFactoryCache::NINE_PATCH_SHADER));
+
+ delete factoryCache;
+
+ END_TEST;
+}
utc-Dali-DragAndDropDetector.cpp
utc-Dali-NPatchUtilities.cpp
utc-Dali-GlView.cpp
+ utc-Dali-GlViewDirectRendering.cpp
)
# List of test harness files (Won't get parsed for test cases)
{
name = uniform.name.substr(0, iter);
auto arrayCount = std::stoi(uniform.name.substr(iter + 1));
+ iter = uniform.name.find("]");
+ std::string suffix;
+ if(iter != std::string::npos && iter + 1 != uniform.name.length())
+ {
+ suffix = uniform.name.substr(iter + 1); // If there is a suffix, it means its an element of an array of struct
+ }
+
for(int i = 0; i < arrayCount; ++i)
{
std::stringstream nss;
- nss << name << "[" << i << "]";
+ nss << name << "[" << i << "]" << suffix;
GetUniformLocation(program, nss.str().c_str()); // Generate a GL loc per element
}
}
for(const auto& data : mCustomUniforms)
{
fprintf(stderr, "\ncustom uniforms: %s\n", data.name.c_str());
- mDefaultUniformBlock.members.emplace_back();
- auto& item = mDefaultUniformBlock.members.back();
auto iter = data.name.find("[", 0);
int numElements = 1;
{
numElements = 1;
}
-
- item.name = baseName;
- item.binding = 0;
- item.bufferIndex = 0;
- item.uniformClass = Graphics::UniformClass::UNIFORM;
- item.type = data.type;
- item.numElements = numElements;
-
- for(int i = 0; i < numElements; ++i)
+ iter = data.name.find("]");
+ std::string suffix;
+ if(iter != std::string::npos && iter + 1 != data.name.length())
{
- std::stringstream elementNameStream;
- elementNameStream << baseName << "[" << i << "]";
+ suffix = data.name.substr(iter + 1); // If there is a suffix, it means it is an element of an array of struct
+ }
- item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
- item.offsets.push_back(offset);
- offset += GetSizeForType(data.type);
+ if(!suffix.empty())
+ {
+ // Write multiple items
+ for(int i = 0; i < numElements; ++i)
+ {
+ std::stringstream elementNameStream;
+ elementNameStream << baseName << "[" << i << "]" << suffix;
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
+ item.name = elementNameStream.str();
+ item.binding = 0;
+ item.offsets.push_back(offset);
+ item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+ item.bufferIndex = 0;
+ item.uniformClass = Graphics::UniformClass::UNIFORM;
+ item.type = data.type;
+ offset += GetSizeForType(data.type);
+ }
+ }
+ else
+ {
+ // Write 1 item with multiple elements
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
+
+ item.name = baseName;
+ item.binding = 0;
+ item.bufferIndex = 0;
+ item.uniformClass = Graphics::UniformClass::UNIFORM;
+ item.type = data.type;
+ item.numElements = numElements;
+
+ for(int i = 0; i < numElements; ++i)
+ {
+ std::stringstream elementNameStream;
+ elementNameStream << baseName << "[" << i << "]";
+ item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+ item.offsets.push_back(offset);
+ offset += GetSizeForType(data.type);
+ }
}
}
else
{
+ // Write 1 item with 1 element
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
item.name = data.name;
item.binding = 0;
item.offsets.push_back(offset);
return mScaleFactor;
}
+ Dali::Accessibility::Address GetAccessibilityAddress()
+ {
+ return {":9.99", "root"};
+ }
+
Dali::PixelData GetScreenshot(Dali::Rect<int32_t> viewArea, float scaleFactor)
{
uint32_t bufferSize = viewArea.width * viewArea.height * 4 ;
{
}
+Accessibility::Address WebEngine::GetAccessibilityAddress()
+{
+ return Internal::Adaptor::GetImplementation(*this).GetAccessibilityAddress();
+}
+
bool WebEngine::HighlightText(const std::string& text, Dali::WebEnginePlugin::FindOption options, uint32_t maxMatchCount)
{
return true;
}
} // namespace Dali;
-
.Add(ImageVisual::Property::URL, TEST_GIF_FILE_NAME)
.Add(ImageVisual::Property::BATCH_SIZE, 1)
.Add(ImageVisual::Property::CACHE_SIZE, 1)
- .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false)
+ .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, true)
+ .Add(ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::DETACHED)
+ .Add(ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::ATTACHED)
.Add(DevelVisual::Property::BORDERLINE_WIDTH, 0.4f));
Property::Map resultMap;
DALI_TEST_CHECK(value);
DALI_TEST_CHECK(value->Get<int>() == 2);
+ value = resultMap.Find(ImageVisual::Property::SYNCHRONOUS_LOADING, Property::BOOLEAN);
+ DALI_TEST_CHECK(value);
+ DALI_TEST_CHECK(value->Get<bool>() == true);
+
+ value = resultMap.Find(ImageVisual::Property::RELEASE_POLICY, Property::INTEGER);
+ DALI_TEST_CHECK(value);
+ DALI_TEST_CHECK(value->Get<int>() == ImageVisual::ReleasePolicy::DETACHED);
+
+ value = resultMap.Find(ImageVisual::Property::LOAD_POLICY, Property::INTEGER);
+ DALI_TEST_CHECK(value);
+ DALI_TEST_CHECK(value->Get<int>() == ImageVisual::LoadPolicy::ATTACHED);
+
value = resultMap.Find(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, "totalFrameNumber");
DALI_TEST_CHECK(value);
DALI_TEST_EQUALS(value->Get<int>(), 4, TEST_LOCATION);
application.SendNotification();
application.Render(20);
- DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ // The first frame is loaded synchronously and load next batch.
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
application.SendNotification();
application.Render();
application.SendNotification();
application.Render(20);
- DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
application.SendNotification();
application.Render();
- DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 3, TEST_LOCATION);
+ DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 2, TEST_LOCATION);
dummyControl.Unparent();
}
--- /dev/null
+/*
+ * Copyright (c) 2022 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 <unistd.h>
+#include <thread>
+
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+// Positive test case for a method
+int UtcDaliGlViewDirectRenderingNew(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliGlViewDirectRenderingNew");
+ GlView view = GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGBA8888);
+ DALI_TEST_CHECK(view);
+
+ auto mode1 = view.GetBackendMode();
+
+ DALI_TEST_EQUALS(mode1, GlView::BackendMode::DIRECT_RENDERING, TEST_LOCATION);
+
+ GlView view2 = GlView::New(GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING, GlView::ColorFormat::RGBA8888);
+ DALI_TEST_CHECK(view2);
+
+ auto mode2 = view2.GetBackendMode();
+ DALI_TEST_EQUALS(mode2, GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingNewN(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliGlViewDirectRenderingNewN");
+ // Invalid backend mode
+ GlView view = GlView::New(GlView::BackendMode(11111), GlView::ColorFormat::RGBA8888);
+ DALI_TEST_CHECK(!view);
+
+ END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGlViewDirectRenderingDownCast(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliGlViewDirectRenderingDownCast");
+
+ GlView view = GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+ BaseHandle handle(view);
+
+ Toolkit::GlView view2 = Toolkit::GlView::DownCast(handle);
+ DALI_TEST_CHECK(view);
+ DALI_TEST_CHECK(view2);
+ DALI_TEST_CHECK(view == view2);
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingCopyAndAssignment(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingCopyAndAssignment");
+
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+ DALI_TEST_CHECK(view);
+
+ GlView copy(view);
+ DALI_TEST_CHECK(view == copy);
+
+ GlView assign;
+ DALI_TEST_CHECK(!assign);
+
+ assign = copy;
+ DALI_TEST_CHECK(assign == view);
+
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingMoveAssignment(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingMoveAssignment");
+
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+ DALI_TEST_EQUALS(1, view.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+ GlView moved;
+ moved = std::move(view);
+ DALI_TEST_CHECK(moved);
+ DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+ DALI_TEST_CHECK(!view);
+
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingSetGraphicsConfigGles20N(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingSetGraphicsConfigGles20");
+ GlView view;
+ try
+ {
+ view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+ DALI_TEST_CHECK(false);
+ }
+ catch(...)
+ {
+ DALI_TEST_CHECK(true);
+ }
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingSetGraphicsConfigGles30(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingSetGraphicsConfigGles30");
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+
+ try
+ {
+ view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_3_0);
+ DALI_TEST_CHECK(true);
+ }
+ catch(...)
+ {
+ DALI_TEST_CHECK(false);
+ }
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingRenderingMode(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingRenderingMode");
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+
+ view.SetRenderingMode(GlView::RenderingMode::ON_DEMAND);
+
+ GlView::RenderingMode mode = view.GetRenderingMode();
+
+ DALI_TEST_EQUALS(GlView::RenderingMode::ON_DEMAND, mode, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingOnSizeSet(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingOnSizeSet");
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+
+ application.GetScene().Add(view);
+
+ application.SendNotification();
+ application.Render();
+
+ Vector3 size(200.0f, 300.0f, 0.0f);
+ view.SetProperty(Actor::Property::SIZE, size);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(view.GetCurrentProperty<Vector3>(Actor::Property::SIZE), size, TEST_LOCATION);
+
+ END_TEST;
+}
+
+namespace DirectRenderingCode
+{
+
+// Internal callback function
+void glInit(void)
+{
+}
+
+int glRenderFrame(void)
+{
+ static unsigned int retFlag = 0;
+ return retFlag++;
+}
+
+void glTerminate(void)
+{
+}
+
+void resizeCB(Vector2 size)
+{
+}
+
+}
+
+int UtcDaliGlViewDirectRenderingRegisterGlCallbacksN(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingRegisterGlCallbacksN");
+ GlView view;
+
+ try
+ {
+ view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate));
+ DALI_TEST_CHECK(false);
+ }
+ catch(...)
+ {
+ DALI_TEST_CHECK(true);
+ }
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingSetResizeCallbackN(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingSetResizeCallback");
+ GlView view;
+
+ try
+ {
+ view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB));
+ DALI_TEST_CHECK(false);
+ }
+ catch(...)
+ {
+ DALI_TEST_CHECK(true);
+ }
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingRenderOnce(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingRenderOnce");
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+
+ try
+ {
+ view.RenderOnce();
+ DALI_TEST_CHECK(true);
+ }
+ catch(...)
+ {
+ DALI_TEST_CHECK(false);
+ }
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingWindowVisibilityChanged(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingWindowVisibilityChanged");
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+ application.GetScene().Add(view);
+ view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS);
+ view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+ view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate));
+ view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB));
+
+ application.SendNotification();
+ application.Render();
+
+ Window window = DevelWindow::Get(view);
+ window.Hide();
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(true);
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingOnScene(void)
+{
+ ToolkitTestApplication application;
+
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+
+ //Onscene
+ application.GetScene().Add(view);
+ view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS);
+ view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+ view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate));
+
+ application.SendNotification();
+ application.Render();
+
+ //Offscene
+ application.GetScene().Remove(view);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(true);
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingControlVisibilityChanged(void)
+{
+ ToolkitTestApplication application;
+
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+ application.GetScene().Add(view);
+
+ application.SendNotification();
+ application.Render();
+
+ view.SetProperty(Actor::Property::VISIBLE, false);
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_CHECK(view.GetCurrentProperty<bool>(Actor::Property::VISIBLE) == false);
+
+ view.SetProperty(Actor::Property::VISIBLE, true);
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_CHECK(view.GetCurrentProperty<bool>(Actor::Property::VISIBLE) == true);
+
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingResize(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingResize");
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+
+ application.GetScene().Add(view);
+ view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+ view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate));
+ view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB));
+ view.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ view.SetProperty(Actor::Property::SIZE, Vector2(360.0f, 360.0f));
+
+ application.SendNotification();
+ application.Render();
+
+ //To GlViewRenderThread can recognize Resize signal the main thread have to sleep.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(true);
+ END_TEST;
+}
+
+int UtcDaliGlViewDirectRenderingTerminateCallback(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliGlViewDirectRenderingTerminateCallback");
+ GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888);
+
+ application.GetScene().Add(view);
+ view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+ view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate));
+ view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB));
+ view.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ view.SetProperty(Actor::Property::SIZE, Vector2(360.0f, 360.0f));
+
+ application.SendNotification();
+ application.Render();
+
+
+
+ //To GlViewRenderThread can recognize Resize signal the main thread have to sleep.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(true);
+ END_TEST;
+}
\ No newline at end of file
#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h>
#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
// resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
-const char* TEST_VECTOR_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insta_camera.json";
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insta_camera.json";
void TestUrl(ImageView imageView, const std::string url)
{
ImageView imageView = ImageView::New();
Property::Map imageMap;
imageMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE);
- imageMap.Add(Toolkit::ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME); // 249x169 image
+ imageMap.Add(Toolkit::ImageVisual::Property::URL, TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME); // 249x169 image
imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, imageMap);
imageView.SetProperty(Actor::Property::SIZE, Vector2(600, 600));
gResourceReadySignalCounter++;
}
+void OnSimpleResourceReadySignal(Control control)
+{
+ // simply increate counter
+ gResourceReadySignalCounter++;
+}
+
} // namespace
int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
END_TEST;
}
+
+int UtcDaliImageViewOnResourceReadySignalWithBrokenAlphaMask01(void)
+{
+ tet_infoline("Test signal handler when image / mask image is broken.");
+
+ ToolkitTestApplication application;
+
+ auto TestResourceReadyUrl = [&application](int eventTriggerCount, bool isSynchronous, const std::string& url, const std::string& mask, const char* location) {
+ gResourceReadySignalCounter = 0;
+
+ Property::Map map;
+ map[Toolkit::ImageVisual::Property::URL] = url;
+ if(!mask.empty())
+ {
+ map[Toolkit::ImageVisual::Property::ALPHA_MASK_URL] = mask;
+ }
+ map[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = isSynchronous;
+
+ ImageView imageView = ImageView::New();
+ imageView[Toolkit::ImageView::Property::IMAGE] = map;
+ imageView[Actor::Property::SIZE] = Vector2(100.0f, 200.0f);
+ imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal);
+
+ application.GetScene().Add(imageView);
+ application.SendNotification();
+ application.Render();
+
+ if(!isSynchronous)
+ {
+ // Wait for loading
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(eventTriggerCount), true, location);
+ }
+ tet_printf("test %s [sync:%d] signal fired\n", url.c_str(), isSynchronous ? 1 : 0);
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 1, location);
+
+ imageView.Unparent();
+ };
+
+ for(int synchronous = 0; synchronous <= 1; synchronous++)
+ {
+ tet_printf("Test normal case (sync:%d)\n", synchronous);
+ TestResourceReadyUrl(1, synchronous, gImage_600_RGB, "", TEST_LOCATION);
+ TestResourceReadyUrl(3, synchronous, gImage_600_RGB, gImage_34_RGBA, TEST_LOCATION); // 3 event trigger required : 2 image load + 1 apply mask
+
+ tet_printf("Test broken image case (sync:%d)\n", synchronous);
+ TestResourceReadyUrl(1, synchronous, "invalid.jpg", "", TEST_LOCATION);
+ TestResourceReadyUrl(2, synchronous, "invalid.jpg", gImage_34_RGBA, TEST_LOCATION);
+
+ tet_printf("Test broken mask image case (sync:%d)\n", synchronous);
+ TestResourceReadyUrl(2, synchronous, gImage_600_RGB, "invalid.png", TEST_LOCATION);
+
+ tet_printf("Test broken both image, mask image case (sync:%d)\n", synchronous);
+ TestResourceReadyUrl(2, synchronous, "invalid.jpg", "invalid.png", TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliImageViewOnResourceReadySignalWithBrokenAlphaMask02(void)
+{
+ tet_infoline("Test signal handler when image try to use cached-and-broken mask image.");
+
+ ToolkitTestApplication application;
+
+ gResourceReadySignalCounter = 0;
+
+ auto TestBrokenMaskResourceReadyUrl = [&application](const std::string& url, const char* location) {
+ Property::Map map;
+ map[Toolkit::ImageVisual::Property::URL] = url;
+ // Use invalid mask url
+ map[Toolkit::ImageVisual::Property::ALPHA_MASK_URL] = "invalid.png";
+
+ ImageView imageView = ImageView::New();
+ imageView[Toolkit::ImageView::Property::IMAGE] = map;
+ imageView[Actor::Property::SIZE] = Vector2(100.0f, 200.0f);
+ imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal);
+
+ application.GetScene().Add(imageView);
+ application.SendNotification();
+ application.Render();
+
+ // Don't unparent imageView, for keep the cache.
+ };
+
+ // Use more than 4 images (The number of LocalImageLoadThread)
+ const std::vector<std::string> testUrlList = {gImage_34_RGBA, gImage_600_RGB, "invalid.jpg" /* invalid url */, TEST_IMAGE_1, TEST_IMAGE_2, TEST_BROKEN_IMAGE_DEFAULT};
+
+ int expectResourceReadySignalCounter = 0;
+
+ for(auto& url : testUrlList)
+ {
+ TestBrokenMaskResourceReadyUrl(url, TEST_LOCATION);
+ expectResourceReadySignalCounter++;
+ }
+
+ // Remain 1 signal due to we use #URL + 1 mask image.
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectResourceReadySignalCounter + 1), true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, expectResourceReadySignalCounter, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliImageViewCheckVariousCaseSendOnResourceReadySignal(void)
+{
+ tet_infoline("Test signal handler various case.");
+
+ ToolkitTestApplication application;
+
+ auto TestResourceReadyUrl = [&application](int eventTriggerCount, bool isSynchronous, bool loadSuccess, const std::string& url, const std::string& mask, const char* location) {
+ gResourceReadySignalCounter = 0;
+
+ Property::Map map;
+ map[Toolkit::ImageVisual::Property::URL] = url;
+ if(!mask.empty())
+ {
+ map[Toolkit::ImageVisual::Property::ALPHA_MASK_URL] = mask;
+ }
+ map[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = isSynchronous;
+
+ ImageView imageView = ImageView::New();
+ imageView[Toolkit::ImageView::Property::IMAGE] = map;
+ imageView[Actor::Property::SIZE] = Vector2(100.0f, 200.0f);
+ imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal);
+
+ application.GetScene().Add(imageView);
+ application.SendNotification();
+ application.Render();
+
+ // Wait for loading
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(eventTriggerCount), true, location);
+
+ tet_printf("test %s [sync:%d] signal fired\n", url.c_str(), isSynchronous ? 1 : 0);
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 1, location);
+ DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(Toolkit::ImageView::Property::IMAGE), loadSuccess ? Toolkit::Visual::ResourceStatus::READY : Toolkit::Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ imageView.Unparent();
+ };
+
+ auto TestAuxiliaryResourceReadyUrl = [&application](bool isSynchronous, bool loadSuccess, const std::string& url, const std::string& auxiliaryUrl, const char* location) {
+ gResourceReadySignalCounter = 0;
+
+ Property::Map map;
+ map[Toolkit::ImageVisual::Property::URL] = url;
+ map[Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE] = auxiliaryUrl;
+ map[Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA] = 0.5f;
+ map[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = isSynchronous;
+
+ ImageView imageView = ImageView::New();
+ imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, map);
+ imageView.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 200.0f));
+ imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal);
+ application.GetScene().Add(imageView);
+
+ application.SendNotification();
+ application.Render();
+
+ if(!isSynchronous)
+ {
+ // Wait for loading
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, location);
+ }
+
+ tet_printf("test %s [sync:%d] signal fired\n", url.c_str(), isSynchronous ? 1 : 0);
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 1, location);
+ DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(Toolkit::ImageView::Property::IMAGE), loadSuccess ? Toolkit::Visual::ResourceStatus::READY : Toolkit::Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ imageView.Unparent();
+ };
+
+ // Case 1 : asynchronous loading
+ tet_printf("Test invalid single simple image Asynchronous\n");
+
+ // Test normal case
+ TestResourceReadyUrl(1, 0, 1, gImage_600_RGB, "", TEST_LOCATION);
+ TestResourceReadyUrl(1, 0, 1, TEST_SVG_FILE_NAME, "", TEST_LOCATION); // 1 rasterize
+ TestResourceReadyUrl(1, 0, 1, TEST_BROKEN_IMAGE_L, "", TEST_LOCATION);
+
+ TestResourceReadyUrl(2, 0, 1, TEST_GIF_FILE_NAME, "", TEST_LOCATION); // 2 image loading - batch size
+ TestResourceReadyUrl(1, 0, 1, TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME, "", TEST_LOCATION); // 1 rasterize
+
+ TestResourceReadyUrl(3, 0, 1, gImage_600_RGB, gImage_34_RGBA, TEST_LOCATION); // 2 image loading + 1 applymask
+
+ TestAuxiliaryResourceReadyUrl(0, 1, TEST_BROKEN_IMAGE_L, gImage_34_RGBA, TEST_LOCATION);
+
+ // Test broken case
+ TestResourceReadyUrl(1, 0, 0, "invalid.jpg", "", TEST_LOCATION);
+ TestResourceReadyUrl(0, 0, 0, "invalid.svg", "", TEST_LOCATION); // 0 rasterize
+ TestResourceReadyUrl(1, 0, 0, "invalid.9.png", "", TEST_LOCATION);
+ TestResourceReadyUrl(1, 0, 0, "invalid.gif", "", TEST_LOCATION); // 1 image loading
+ TestResourceReadyUrl(0, 0, 0, "invalid.json", "", TEST_LOCATION); // 0 rasterize
+
+ TestResourceReadyUrl(2, 0, 0, "invalid.jpg", "invalid.png", TEST_LOCATION); // 2 image loading
+ TestResourceReadyUrl(2, 0, 1, gImage_600_RGB, "invalid.png", TEST_LOCATION); // 2 image loading
+ TestResourceReadyUrl(2, 0, 0, "invalid.jpg", gImage_34_RGBA, TEST_LOCATION); // 2 image loading
+
+ TestAuxiliaryResourceReadyUrl(0, 0, "invalid.9.png", "invalid.png", TEST_LOCATION);
+ TestAuxiliaryResourceReadyUrl(0, 1, TEST_BROKEN_IMAGE_L, "invalid.png", TEST_LOCATION);
+ TestAuxiliaryResourceReadyUrl(0, 0, "invalid.9.png", gImage_34_RGBA, TEST_LOCATION);
+
+ // Case 2 : Synchronous loading
+ tet_printf("Test invalid single simple image Synchronous\n");
+
+ // Test normal case
+ TestResourceReadyUrl(0, 1, 1, gImage_600_RGB, "", TEST_LOCATION);
+ TestResourceReadyUrl(0, 1, 1, TEST_SVG_FILE_NAME, "", TEST_LOCATION); // synchronous rasterize
+ TestResourceReadyUrl(0, 1, 1, TEST_BROKEN_IMAGE_L, "", TEST_LOCATION);
+
+ TestResourceReadyUrl(1, 1, 1, TEST_GIF_FILE_NAME, "", TEST_LOCATION); // first frame image loading sync + second frame image loading async
+ TestResourceReadyUrl(0, 1, 1, TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME, "", TEST_LOCATION); // synchronous rasterize
+
+ TestResourceReadyUrl(0, 1, 1, gImage_600_RGB, gImage_34_RGBA, TEST_LOCATION);
+
+ TestAuxiliaryResourceReadyUrl(1, 1, TEST_BROKEN_IMAGE_L, gImage_34_RGBA, TEST_LOCATION);
+
+ // Test broken case
+ TestResourceReadyUrl(0, 1, 0, "invalid.jpg", "", TEST_LOCATION);
+ TestResourceReadyUrl(0, 1, 0, "invalid.svg", "", TEST_LOCATION); // 0 rasterize
+ TestResourceReadyUrl(0, 1, 0, "invalid.9.png", "", TEST_LOCATION);
+ TestResourceReadyUrl(0, 1, 0, "invalid.gif", "", TEST_LOCATION);
+ TestResourceReadyUrl(0, 1, 0, "invalid.json", "", TEST_LOCATION); // 0 rasterize
+
+ TestResourceReadyUrl(0, 1, 0, "invalid.jpg", "invalid.png", TEST_LOCATION);
+ TestResourceReadyUrl(0, 1, 1, gImage_600_RGB, "invalid.png", TEST_LOCATION);
+ TestResourceReadyUrl(0, 1, 0, "invalid.jpg", gImage_34_RGBA, TEST_LOCATION);
+
+ TestAuxiliaryResourceReadyUrl(1, 0, "invalid.9.png", "invalid.png", TEST_LOCATION);
+ TestAuxiliaryResourceReadyUrl(1, 1, TEST_BROKEN_IMAGE_L, "invalid.png", TEST_LOCATION);
+ TestAuxiliaryResourceReadyUrl(1, 0, "invalid.9.png", gImage_34_RGBA, TEST_LOCATION);
+
+ END_TEST;
+}
application.SendNotification();
application.Render();
- // Check that the focus is successfully to clear
- DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+ // Since no focus has been moved, the current focus actor is the same.
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
// Make the second actor focusableInTouchMode
second.SetProperty(DevelActor::Property::TOUCH_FOCUSABLE, true);
END_TEST;
}
+
+int UtcDaliKeyboardFocusManagerWithUserInteractionEnabled(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" UtcDaliKeyboardFocusManagerWithUserInteractionEnabled");
+
+ KeyboardFocusManager manager = KeyboardFocusManager::Get();
+ DALI_TEST_CHECK(manager);
+
+ // Create the first actor and add it to the stage
+ Actor first = Actor::New();
+ first.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+ application.GetScene().Add(first);
+
+ // Create the second actor and add it to the first actor.
+ Actor second = Actor::New();
+ second.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+ first.Add(second);
+
+ // Check that no actor is being focused yet.
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+ // Check that the focus is set on the first actor
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+ // Set USER_INTERACTION_ENABLED false.
+ second.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, false);
+
+ // Check that it will fail to set focus on the second actor as it's not userInteractionEnabled
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == false);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+ // Set KeyboardFocusableChildren true.
+ second.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, true);
+
+ // Check that the focus is set on the second actor
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+ END_TEST;
+}
\ No newline at end of file
#include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
#include <dali-toolkit/devel-api/text/rendering-backend.h>
#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+
+#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/adaptor-framework/clipboard.h>
#include <dali/devel-api/adaptor-framework/key-devel.h>
#include <dali/devel-api/text-abstraction/font-client.h>
editor.SetProperty(TextEditor::Property::HORIZONTAL_ALIGNMENT, "END");
DALI_TEST_EQUALS(editor.GetProperty<std::string>(TextEditor::Property::HORIZONTAL_ALIGNMENT), "END", TEST_LOCATION);
+ // Check that the Alignment properties can be correctly set
+ editor.SetProperty(DevelTextEditor::Property::VERTICAL_ALIGNMENT, "BOTTOM");
+ DALI_TEST_EQUALS(editor.GetProperty<std::string>(DevelTextEditor::Property::VERTICAL_ALIGNMENT), "BOTTOM", TEST_LOCATION);
+ editor.SetProperty(DevelTextEditor::Property::VERTICAL_ALIGNMENT, "CENTER");
+ DALI_TEST_EQUALS(editor.GetProperty<std::string>(DevelTextEditor::Property::VERTICAL_ALIGNMENT), "CENTER", TEST_LOCATION);
+ editor.SetProperty(DevelTextEditor::Property::VERTICAL_ALIGNMENT, "TOP");
+ DALI_TEST_EQUALS(editor.GetProperty<std::string>(DevelTextEditor::Property::VERTICAL_ALIGNMENT), "TOP", TEST_LOCATION);
+
// Check scroll properties.
editor.SetProperty(TextEditor::Property::SCROLL_THRESHOLD, 1.f);
DALI_TEST_EQUALS(editor.GetProperty<float>(TextEditor::Property::SCROLL_THRESHOLD), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
application.SendNotification();
application.Render();
+ textEditor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, true);
+ DALI_TEST_EQUALS(textEditor.GetProperty(DevelActor::Property::USER_INTERACTION_ENABLED).Get<bool>(), true, TEST_LOCATION);
+
textEditor.SetKeyInputFocus();
textEditor.SetProperty(DevelTextEditor::Property::ENABLE_EDITING, false);
application.ProcessEvent(GenerateKey("D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
DALI_TEST_EQUALS(textEditor.GetProperty(TextEditor::Property::TEXT).Get<std::string>(), "D", TEST_LOCATION);
DALI_TEST_EQUALS(textEditor.GetProperty(DevelTextEditor::Property::ENABLE_EDITING).Get<bool>(), true, TEST_LOCATION);
+ // Check the user interaction enabled and for coverage
+ DevelTextEditor::SelectWholeText(textEditor);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ textEditor.SetKeyInputFocus();
+ textEditor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, false);
+ application.ProcessEvent(GenerateKey("D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(textEditor.GetProperty(TextEditor::Property::TEXT).Get<std::string>(), "D", TEST_LOCATION);
+ DALI_TEST_EQUALS(textEditor.GetProperty(DevelActor::Property::USER_INTERACTION_ENABLED).Get<bool>(), false, TEST_LOCATION);
+
END_TEST;
}
END_TEST;
}
+int UtcDaliToolkitTextEditorMarkupRelativeLineHeight(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliToolkitTextEditorMarkupRelativeLineHeight");
+
+ TextEditor editor = TextEditor::New();
+ editor.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+ editor.SetProperty(TextEditor::Property::POINT_SIZE, 10);
+ editor.SetProperty(TextEditor::Property::TEXT, "line 1\nline 2\nline 3\nline 4\nline 5");
+ editor.SetProperty(DevelTextEditor::Property::RELATIVE_LINE_SIZE, 1.0f);
+ editor.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+ editor.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
+
+ TextEditor editorSingleLineParagraph = TextEditor::New();
+ editorSingleLineParagraph.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+ editorSingleLineParagraph.SetProperty(TextEditor::Property::POINT_SIZE, 10);
+ editorSingleLineParagraph.SetProperty(TextEditor::Property::TEXT, "<p>line 1</p><p rel-line-height=0.5>line 2</p>line 3<p rel-line-height=3>line 4</p>line 5");
+ editorSingleLineParagraph.SetProperty(DevelTextEditor::Property::RELATIVE_LINE_SIZE, 1.0f);
+ editorSingleLineParagraph.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+ editorSingleLineParagraph.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
+
+ TextEditor editorMultiLineParagraph = TextEditor::New();
+ editorMultiLineParagraph.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+ editorMultiLineParagraph.SetProperty(TextEditor::Property::POINT_SIZE, 10);
+ editorMultiLineParagraph.SetProperty(TextEditor::Property::TEXT, "<p>line 1</p><p rel-line-height=0.5>line\n2</p>line 3<p rel-line-height=3>line\n4</p>line 5");
+ editorMultiLineParagraph.SetProperty(DevelTextEditor::Property::RELATIVE_LINE_SIZE, 1.0f);
+ editorMultiLineParagraph.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+ editorMultiLineParagraph.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
+
+ application.GetScene().Add(editor);
+ application.GetScene().Add(editorSingleLineParagraph);
+ application.GetScene().Add(editorMultiLineParagraph);
+ application.SendNotification();
+ application.Render();
+
+ Vector3 naturalSize = editor.GetNaturalSize();
+ Vector3 relativeSingleNaturalSize = editorSingleLineParagraph.GetNaturalSize();
+ Vector3 relativeMultiNaturalSize = editorMultiLineParagraph.GetNaturalSize();
+
+ float lineSize = naturalSize.y / 5.0f; //total size/number of lines
+
+ //no effect of relative line size for paragraph with single line
+ DALI_TEST_EQUALS(naturalSize.y, relativeSingleNaturalSize.y, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(lineSize*8.5f, relativeMultiNaturalSize.y, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliToolkitTextEditorRelativeLineHeight(void)
{
ToolkitTestApplication application;
END_TEST;
}
+int UtcDaliTextEditorLineSpacingKeyArrowDown(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliTextEditorLineSpacingKeyArrowDown");
+
+ TextEditor editor = TextEditor::New();
+ DALI_TEST_CHECK(editor);
+
+ application.GetScene().Add(editor);
+
+ std::string cutText = "";
+ std::string copiedText = "";
+
+ editor.SetProperty(TextEditor::Property::TEXT, "l1\nl2\nl3\n4");
+ editor.SetProperty(TextEditor::Property::POINT_SIZE, 10.f);
+ editor.SetProperty(Actor::Property::SIZE, Vector2(300.f, 200.f));
+ editor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ editor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ editor.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
+ editor.SetProperty(TextEditor::Property::LINE_SPACING, -15);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Tap on the text editor
+ TestGenerateTap(application, 1.0f, 1.0f);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Move to second line of the text.
+ application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(editor.GetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION).Get<int>(), 3, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliTextEditorNegativeLineSpacingWithEllipsis(void)
{
ToolkitTestApplication application;
#include <dali/integration-api/events/key-event-integ.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/actors/actor-devel.h>
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
application.SendNotification();
application.Render();
+ textField.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, true);
+ DALI_TEST_EQUALS(textField.GetProperty(DevelActor::Property::USER_INTERACTION_ENABLED).Get<bool>(), true, TEST_LOCATION);
+
textField.SetKeyInputFocus();
textField.SetProperty(DevelTextField::Property::ENABLE_EDITING, false);
application.ProcessEvent(GenerateKey("D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
DALI_TEST_EQUALS(textField.GetProperty(TextField::Property::TEXT).Get<std::string>(), "D", TEST_LOCATION);
DALI_TEST_EQUALS(textField.GetProperty(DevelTextField::Property::ENABLE_EDITING).Get<bool>(), true, TEST_LOCATION);
+ // Check the user interaction enabled and for coverage
+ DevelTextField::SelectWholeText(textField);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ textField.SetKeyInputFocus();
+ textField.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, false);
+ application.ProcessEvent(GenerateKey("D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(textField.GetProperty(TextField::Property::TEXT).Get<std::string>(), "D", TEST_LOCATION);
+ DALI_TEST_EQUALS(textField.GetProperty(DevelActor::Property::USER_INTERACTION_ENABLED).Get<bool>(), false, TEST_LOCATION);
+
END_TEST;
}
END_TEST;
}
+int UtcDaliToolkitTextLabelMarkupRelativeLineHeight(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliToolkitTextLabelMarkupRelativeLineHeight");
+
+ TextLabel label = TextLabel::New();
+ label.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+ label.SetProperty(TextLabel::Property::POINT_SIZE, 10);
+ label.SetProperty(TextLabel::Property::MULTI_LINE, true);
+ label.SetProperty(TextLabel::Property::TEXT, "line 1\nline 2\nline 3\nline 4\nline 5");
+ label.SetProperty(DevelTextLabel::Property::RELATIVE_LINE_SIZE, 1.0f);
+ label.SetProperty(TextLabel::Property::ELLIPSIS, false);
+ label.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
+
+ TextLabel labelSingleLineParagraph = TextLabel::New();
+ labelSingleLineParagraph.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+ labelSingleLineParagraph.SetProperty(TextLabel::Property::POINT_SIZE, 10);
+ labelSingleLineParagraph.SetProperty(TextLabel::Property::MULTI_LINE, true);
+ labelSingleLineParagraph.SetProperty(TextLabel::Property::TEXT, "<p>line 1</p><p rel-line-height=0.5>line 2</p>line 3<p rel-line-height=3>line 4</p>line 5");
+ labelSingleLineParagraph.SetProperty(DevelTextLabel::Property::RELATIVE_LINE_SIZE, 1.0f);
+ labelSingleLineParagraph.SetProperty(TextLabel::Property::ELLIPSIS, false);
+ labelSingleLineParagraph.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
+
+ TextLabel labelMultiLineParagraph = TextLabel::New();
+ labelMultiLineParagraph.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+ labelMultiLineParagraph.SetProperty(TextLabel::Property::POINT_SIZE, 10);
+ labelMultiLineParagraph.SetProperty(TextLabel::Property::MULTI_LINE, true);
+ labelMultiLineParagraph.SetProperty(TextLabel::Property::TEXT, "<p>line 1</p><p rel-line-height=0.5>line\n2</p>line 3<p rel-line-height=3>line\n4</p>line 5");
+ labelMultiLineParagraph.SetProperty(DevelTextLabel::Property::RELATIVE_LINE_SIZE, 1.0f);
+ labelMultiLineParagraph.SetProperty(TextLabel::Property::ELLIPSIS, false);
+ labelMultiLineParagraph.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
+
+ application.GetScene().Add(label);
+ application.GetScene().Add(labelSingleLineParagraph);
+ application.GetScene().Add(labelMultiLineParagraph);
+ application.SendNotification();
+ application.Render();
+
+ Vector3 naturalSize = label.GetNaturalSize();
+ Vector3 relativeSingleNaturalSize = labelSingleLineParagraph.GetNaturalSize();
+ Vector3 relativeMultiNaturalSize = labelMultiLineParagraph.GetNaturalSize();
+
+ float lineSize = naturalSize.y / 5.0f; //total size/number of lines
+
+ //no effect of relative line size for paragraph with single line
+ DALI_TEST_EQUALS(naturalSize.y, relativeSingleNaturalSize.y, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(lineSize*8.5f, relativeMultiNaturalSize.y, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliToolkitTextLabelRelativeLineHeight(void)
{
ToolkitTestApplication application;
popup.SetProperty(TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE, "POPUP_PASTE_BUTTON_ICON_IMAGE");
popup.SetProperty(TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE, "POPUP_SELECT_BUTTON_ICON_IMAGE");
popup.SetProperty(TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE, "POPUP_SELECT_ALL_BUTTON_ICON_IMAGE");
+ popup.SetProperty(TextSelectionPopup::Property::POPUP_PRESSED_IMAGE, "POPUP_PRESSED_IMAGE");
DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE).Get<std::string>(), "POPUP_CLIPBOARD_BUTTON_ICON_IMAGE", TEST_LOCATION);
DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE).Get<std::string>(), "POPUP_CUT_BUTTON_ICON_IMAGE", TEST_LOCATION);
DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE).Get<std::string>(), "POPUP_PASTE_BUTTON_ICON_IMAGE", TEST_LOCATION);
DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE).Get<std::string>(), "POPUP_SELECT_BUTTON_ICON_IMAGE", TEST_LOCATION);
DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE).Get<std::string>(), "POPUP_SELECT_ALL_BUTTON_ICON_IMAGE", TEST_LOCATION);
+ DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_PRESSED_IMAGE).Get<std::string>(), "POPUP_PRESSED_IMAGE", TEST_LOCATION);
END_TEST;
}
END_TEST;
}
+
+int UtcDaliToolkitTextSelectionPopupDurationProperties(void)
+{
+ ToolkitTestApplication application;
+ TextSelectionPopup popup = TextSelectionPopup::New(nullptr);
+
+ const float popupFadeInDuration = 5.0f;
+ const float popupFadeOutDuration = 10.0f;
+ popup.SetProperty(TextSelectionPopup::Property::POPUP_FADE_IN_DURATION, popupFadeInDuration);
+ popup.SetProperty(TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION, popupFadeOutDuration);
+
+ DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_FADE_IN_DURATION).Get<float>(), popupFadeInDuration, TEST_LOCATION);
+ DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION).Get<float>(), popupFadeOutDuration, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionPopupColorProperties(void)
+{
+ ToolkitTestApplication application;
+ TextSelectionPopup popup = TextSelectionPopup::New(nullptr);
+
+ popup.SetProperty(TextSelectionPopup::Property::POPUP_DIVIDER_COLOR, Color::RED);
+ popup.SetProperty(TextSelectionPopup::Property::POPUP_ICON_COLOR, Color::BLUE);
+ popup.SetProperty(TextSelectionPopup::Property::POPUP_PRESSED_COLOR, Color::BLACK);
+
+ DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_DIVIDER_COLOR).Get<Vector4>(), Color::RED, TEST_LOCATION);
+ DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_ICON_COLOR).Get<Vector4>(), Color::BLUE, TEST_LOCATION);
+ DALI_TEST_EQUALS(popup.GetProperty(TextSelectionPopup::Property::POPUP_PRESSED_COLOR).Get<Vector4>(), Color::BLACK, TEST_LOCATION);
+
+ END_TEST;
+}
\ No newline at end of file
DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
}
+int gResourceReadySignalCounter;
+
+void OnResourceReadySignal(Control control)
+{
+ gResourceReadySignalCounter++;
+}
+
} // namespace
void dali_visual_factory_startup(void)
propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(2, 2, 2, 2));
{
- tet_infoline("whole grid");
+ tet_infoline("whole grid (2,2,2,2) async");
Visual::Base visual = factory.CreateVisual(propertyMap);
DALI_TEST_CHECK(visual);
propertyMap.Clear();
propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
+ propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(2, 2, 2, 2));
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+ {
+ tet_infoline("whole grid (2,2,2,2) sync");
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New(true);
+ TestVisualRender(application, actor, visual);
+
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+ Vector2 naturalSize(0.0f, 0.0f);
+ visual.GetNaturalSize(naturalSize);
+ DALI_TEST_EQUALS(naturalSize, Vector2(imageSize.GetWidth(), imageSize.GetHeight()), TEST_LOCATION);
+ }
+
+ propertyMap.Clear();
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(1, 1, 1, 1));
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
{
- tet_infoline("whole grid");
+ tet_infoline("whole grid (1,1,1,1) sync : for testing same image, different border");
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New(true);
+ TestVisualRender(application, actor, visual);
+
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+ Vector2 naturalSize(0.0f, 0.0f);
+ visual.GetNaturalSize(naturalSize);
+ DALI_TEST_EQUALS(naturalSize, Vector2(imageSize.GetWidth(), imageSize.GetHeight()), TEST_LOCATION);
+ }
+
+ propertyMap.Clear();
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
+ propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(1, 1, 1, 1));
+ {
+ tet_infoline("whole grid (1,1,1,1) async");
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New(true);
+ TestVisualRender(application, actor, visual);
+
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+ Vector2 naturalSize(0.0f, 0.0f);
+ visual.GetNaturalSize(naturalSize);
+ DALI_TEST_EQUALS(naturalSize, Vector2(imageSize.GetWidth(), imageSize.GetHeight()), TEST_LOCATION);
+ }
+
+ propertyMap.Clear();
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
+ propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(3, 3, 3, 3));
+ {
+ tet_infoline("whole grid (3,3,3,3) async");
Visual::Base visual = factory.CreateVisual(propertyMap);
DALI_TEST_CHECK(visual);
END_TEST;
}
+int UtcDaliVisualFactoryGetNPatchVisual9(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliVisualFactoryGetNPatchVisual9: Request n-patch visual sync during another n-patch visual load image asynchronously");
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK(factory);
+
+ Property::Map propertyMap;
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_NPATCH_FILE_NAME);
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New(true);
+
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+ actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+
+ application.GetScene().Add(actor);
+
+ propertyMap.Clear();
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_NPATCH_FILE_NAME);
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+ Visual::Base visual2 = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual2);
+
+ DummyControl actor2 = DummyControl::New(true);
+
+ DummyControlImpl& dummyImpl2 = static_cast<DummyControlImpl&>(actor2.GetImplementation());
+ dummyImpl2.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual2);
+
+ actor2.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+ DALI_TEST_EQUALS(actor2.GetRendererCount(), 0u, TEST_LOCATION);
+
+ application.GetScene().Add(actor2);
+
+ application.SendNotification();
+ application.Render();
+
+ application.SendNotification();
+ application.Render();
+
+ // Async loading is not finished yet.
+ {
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+ }
+ // Sync loading is finished.
+ {
+ Renderer renderer = actor2.GetRendererAt(0);
+ auto textures = renderer.GetTextures();
+
+ DALI_TEST_EQUALS(textures.GetTextureCount(), 1, TEST_LOCATION);
+ }
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+ // Async loading is finished.
+ {
+ Renderer renderer = actor.GetRendererAt(0);
+ auto textures = renderer.GetTextures();
+
+ DALI_TEST_EQUALS(textures.GetTextureCount(), 1, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual10(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliVisualFactoryGetNPatchVisual10: Request same 9-patch visual with a different border");
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK(factory);
+
+ // Get actual size of test image
+ ImageDimensions imageSize = Dali::GetClosestImageSize(gImage_34_RGBA);
+
+ Property::Map propertyMap;
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
+ propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(2, 2, 2, 2));
+ {
+ tet_infoline("whole grid (2,2,2,2) async");
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New(true);
+ TestVisualAsynchronousRender(application, actor, visual);
+
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+ Vector2 naturalSize(0.0f, 0.0f);
+ visual.GetNaturalSize(naturalSize);
+ DALI_TEST_EQUALS(naturalSize, Vector2(imageSize.GetWidth(), imageSize.GetHeight()), TEST_LOCATION);
+ }
+
+ propertyMap.Clear();
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
+ propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(1, 1, 1, 1));
+ {
+ tet_infoline("whole grid (1,1,1,1) async. Check whether we use cached texture");
+ // We don't use dummyControl here
+
+ const int expectResourceReadySignalCounter = 10;
+ gResourceReadySignalCounter = 0;
+
+ for(int i = 0; i < expectResourceReadySignalCounter; i++)
+ {
+ ImageView imageView = ImageView::New();
+ imageView[Toolkit::ImageView::Property::IMAGE] = propertyMap;
+ imageView.ResourceReadySignal().Connect(&OnResourceReadySignal);
+ application.GetScene().Add(imageView);
+ }
+
+ // Dont wait for loading. All border use cached texture.
+
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, expectResourceReadySignalCounter, TEST_LOCATION);
+ }
+
+ propertyMap.Clear();
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::N_PATCH);
+ propertyMap.Insert(ImageVisual::Property::URL, gImage_34_RGBA);
+ propertyMap.Insert(ImageVisual::Property::BORDER, Rect<int>(1, 2, 1, 2));
+ {
+ tet_infoline("whole grid (1,2,1,2) async. Check whether we use cached texture");
+ // We don't use dummyControl here
+
+ const int expectResourceReadySignalCounter = 10;
+ gResourceReadySignalCounter = 0;
+
+ for(int i = 0; i < expectResourceReadySignalCounter; i++)
+ {
+ ImageView imageView = ImageView::New();
+ imageView[Toolkit::ImageView::Property::IMAGE] = propertyMap;
+ imageView.ResourceReadySignal().Connect(&OnResourceReadySignal);
+ application.GetScene().Add(imageView);
+ }
+
+ // Dont wait for loading. All border use cached texture.
+
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, expectResourceReadySignalCounter, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
int UtcDaliNPatchVisualAuxiliaryImage01(void)
{
ToolkitTestApplication application;
#ifndef DALI_SCENE_LOADER_GLTF2_ASSET_H_
#define DALI_SCENE_LOADER_GLTF2_ASSET_H_
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
struct Asset
{
+ std::string_view mGenerator;
std::string_view mVersion;
};
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
const std::string SCALE_PROPERTY("scale");
const std::string BLEND_SHAPE_WEIGHTS_UNIFORM("uBlendShapeWeight");
+const std::string MRENDERER_MODEL_IDENTIFICATION("M-Renderer");
+
+const std::string ROOT_NODE_NAME("RootNode");
+const Vector3 SCALE_TO_ADJUST(100.0f, 100.0f, 100.0f);
+
const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{
Geometry::POINTS,
Geometry::LINES,
}
}
-void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, ConversionContext& cctx)
+void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, ConversionContext& cctx, bool isMRendererModel)
{
auto& output = cctx.mOutput;
auto& scene = output.mScene;
nodeDef->mPosition = node.mTranslation;
nodeDef->mOrientation = node.mRotation;
nodeDef->mScale = node.mScale;
+
+ if(isMRendererModel && node.mName == ROOT_NODE_NAME && node.mScale == SCALE_TO_ADJUST)
+ {
+ nodeDef->mScale *= 0.01f;
+ }
}
return nodeDef;
for(auto& n : node.mChildren)
{
- ConvertNode(*n, n.GetIndex(), idx, cctx);
+ ConvertNode(*n, n.GetIndex(), idx, cctx, isMRendererModel);
}
}
-void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx)
+void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx, bool isMRendererModel)
{
auto& outScene = cctx.mOutput.mScene;
Index rootIdx = outScene.GetNodeCount();
break;
case 1:
- ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, cctx);
+ ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, cctx, isMRendererModel);
outScene.AddRootNode(rootIdx);
break;
for(auto& n : scene.mNodes)
{
- ConvertNode(*n, n.GetIndex(), rootIdx, cctx);
+ ConvertNode(*n, n.GetIndex(), rootIdx, cctx, isMRendererModel);
}
break;
}
}
}
-void ConvertNodes(const gt::Document& doc, ConversionContext& cctx)
+void ConvertNodes(const gt::Document& doc, ConversionContext& cctx, bool isMRendererModel)
{
- ConvertSceneNodes(*doc.mScene, cctx);
+ ConvertSceneNodes(*doc.mScene, cctx, isMRendererModel);
for(uint32_t i = 0, i1 = doc.mScene.GetIndex(); i < i1; ++i)
{
- ConvertSceneNodes(doc.mScenes[i], cctx);
+ ConvertSceneNodes(doc.mScenes[i], cctx, isMRendererModel);
}
for(uint32_t i = doc.mScene.GetIndex() + 1; i < doc.mScenes.size(); ++i)
{
- ConvertSceneNodes(doc.mScenes[i], cctx);
+ ConvertSceneNodes(doc.mScenes[i], cctx, isMRendererModel);
}
}
gt::Document doc;
- auto& rootObj = js::Cast<json_object_s>(*root);
- auto jsAsset = js::FindObjectChild("asset", rootObj);
- auto jsAssetVersion = js::FindObjectChild("version", js::Cast<json_object_s>(*jsAsset));
- doc.mAsset.mVersion = js::Read::StringView(*jsAssetVersion);
+ auto& rootObj = js::Cast<json_object_s>(*root);
+ auto jsAsset = js::FindObjectChild("asset", rootObj);
+
+ auto jsAssetVersion = js::FindObjectChild("version", js::Cast<json_object_s>(*jsAsset));
+ if(jsAssetVersion)
+ {
+ doc.mAsset.mVersion = js::Read::StringView(*jsAssetVersion);
+ }
+
+ bool isMRendererModel(false);
+ auto jsAssetGenerator = js::FindObjectChild("generator", js::Cast<json_object_s>(*jsAsset));
+ if(jsAssetGenerator)
+ {
+ doc.mAsset.mGenerator = js::Read::StringView(*jsAssetGenerator);
+ isMRendererModel = (doc.mAsset.mGenerator.find(MRENDERER_MODEL_IDENTIFICATION) != std::string_view::npos);
+ }
+
gt::SetRefReaderObject(doc);
DOCUMENT_READER.Read(rootObj, doc);
ConvertMaterials(doc, cctx);
ConvertMeshes(doc, cctx);
- ConvertNodes(doc, cctx);
+ ConvertNodes(doc, cctx, isMRendererModel);
ConvertAnimations(doc, cctx);
ProcessSkins(doc, cctx);
* @note If the value is less than 1, the lines could to be overlapped.
*/
RELATIVE_LINE_SIZE,
+
+ /**
+ * @brief The line vertical alignment.
+ * @details Name "verticalAlignment", type Property::STRING or type VerticalAlignment::Type (Property::INTEGER).
+ * Values "TOP", "CENTER", "BOTTOM", default TOP.
+ * @note Return type is Property::STRING
+ */
+ VERTICAL_ALIGNMENT,
};
} // namespace Property
bool IsFocusable(Actor& actor)\r
{\r
return (actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) &&\r
+ actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED) &&\r
actor.GetProperty<bool>(Actor::Property::VISIBLE) &&\r
actor.GetProperty<Vector4>(Actor::Property::WORLD_COLOR).a > FULLY_TRANSPARENT);\r
}\r
/*
-* Copyright (c) 2021 Samsung Electronics Co., Ltd.
+* Copyright (c) 2022 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.
case Dali::Pixel::DEPTH_FLOAT:
case Dali::Pixel::DEPTH_STENCIL:
case Dali::Pixel::R11G11B10F:
+ case Dali::Pixel::CHROMINANCE_U:
+ case Dali::Pixel::CHROMINANCE_V:
{
DALI_LOG_ERROR("Pixel format not compatible.\n");
byteOffset = 0;
--- /dev/null
+/*
+ * Copyright (c) 2021 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-toolkit/internal/controls/gl-view/drawable-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/rendering/renderer.h>
+
+namespace Dali::Toolkit::Internal
+{
+Dali::Toolkit::GlView DrawableView::New()
+{
+ auto* impl = new DrawableView();
+ Dali::Toolkit::GlView handle = Dali::Toolkit::GlView(*impl);
+ impl->Initialize();
+ return handle;
+}
+
+DrawableView::DrawableView()
+: Dali::Toolkit::Internal::GlViewImpl( GlView::BackendMode::DIRECT_RENDERING ),
+ mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS),
+ mDepth(false),
+ mStencil(false),
+ mMSAA(0)
+{
+ mRenderCallback = RenderCallback::New( this, &DrawableView::OnRenderCallback);
+}
+
+DrawableView::~DrawableView() = default;
+
+void DrawableView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
+{
+ mOnInitCallback.reset( initCallback );
+ mOnRenderCallback.reset(renderFrameCallback );
+ mOnTerminateCallback. reset( terminateCallback );
+}
+
+void DrawableView::SetResizeCallback(CallbackBase* resizeCallback)
+{
+ mOnResizeCallback.reset( resizeCallback );
+}
+
+bool DrawableView::SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version)
+{
+ DALI_LOG_ERROR( "DrawableView::SetGraphicsConfig() is currently not implemented");
+
+ return true;
+}
+
+void DrawableView::SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode)
+{
+ mRenderingMode = mode;
+ Renderer renderer = Self().GetRendererAt(0);
+
+ if(mRenderingMode == Dali::Toolkit::GlView::RenderingMode::ON_DEMAND)
+ {
+ renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
+ }
+ else
+ {
+ renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
+ }
+}
+
+Dali::Toolkit::GlView::RenderingMode DrawableView::GetRenderingMode() const
+{
+ return mRenderingMode;
+}
+
+void DrawableView::RenderOnce()
+{
+ // Ignored.
+ // TODO: without rendering on the separate thread the RenderOnce won't
+ // work as expected. Potential implementation of threading may enable that
+ // feature.
+}
+
+void DrawableView::OnInitialize()
+{
+ AddRenderer();
+
+ // Adding VisibilityChange Signal.
+ Actor self = Self();
+ Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &DrawableView::OnControlVisibilityChanged);
+}
+
+void DrawableView::OnSizeSet(const Vector3& targetSize)
+{
+ Control::OnSizeSet(targetSize);
+
+ mSurfaceSize = targetSize;
+
+ // If the callbacks are set then schedule execution of resize callback
+ if(mRenderCallback && mOnResizeCallback)
+ {
+ mSurfaceResized = true;
+ }
+}
+
+void DrawableView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
+{
+ // Ignored due to lack dedicated rendering thread
+}
+
+void DrawableView::OnWindowVisibilityChanged(Window window, bool visible)
+{
+ // Ignored due to lack dedicated rendering thread
+}
+
+void DrawableView::OnSceneConnection(int depth)
+{
+ Control::OnSceneConnection(depth);
+
+ Actor self = Self();
+ Window window = DevelWindow::Get(self);
+
+ // Despite OnWindowVisibilityChanged() is ignored it still should follow
+ // the designed behaviour of GlView so signal is connected regardless
+ if(window)
+ {
+ DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged);
+ }
+}
+
+void DrawableView::OnSceneDisconnection()
+{
+ Control::OnSceneDisconnection();
+}
+
+void DrawableView::AddRenderer()
+{
+ Actor self = Self();
+ Renderer renderer = Renderer::New( *mRenderCallback );
+ self.AddRenderer(renderer);
+}
+
+bool DrawableView::OnRenderCallback( const RenderCallbackInput& renderCallbackInput )
+{
+ // Init state
+ if( mCurrentViewState == ViewState::INIT )
+ {
+ if(mOnInitCallback)
+ {
+ CallbackBase::Execute(*mOnInitCallback);
+ }
+ mCurrentViewState = ViewState::RENDER;
+ }
+
+ int renderFrameResult = 0;
+ if( mCurrentViewState == ViewState::RENDER )
+ {
+ // The mSurfaceResized is set by another thread so atomic check must be provided
+ bool expected{ true };
+ if(mSurfaceResized.compare_exchange_weak( expected, false,
+ std::memory_order_release,
+ std::memory_order_relaxed
+ ) && mOnResizeCallback)
+ {
+ CallbackBase::Execute(*mOnResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
+ }
+
+ if(mOnRenderCallback)
+ {
+ renderFrameResult = CallbackBase::ExecuteReturn<int>(*mOnRenderCallback);
+ if(renderFrameResult)
+ {
+ // TODO: may be utilized for RenderOnce feature
+ }
+ }
+ }
+
+ // The terminate callback isn't easy to implement for DR. The NativeImage backend
+ // calls it when the GlView is being destroyed. For DrawableView it means that
+ // the RenderCallback won't be executed (as it is a part of graphics pipeline).
+ // We don't have currenty no way to know whether the View will be destroyed and
+ // to execute last native draw command in the pipeline.
+ //
+ // else if( mCurrentViewState == ViewState::TERMINATE )
+ // {
+ // CallbackBase::Execute(*mOnTerminateCallback);
+ // }
+
+ return true;
+}
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_DRAWABLE_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_DRAWABLE_VIEW_H
+
+/*
+ * Copyright (c) 2021 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/public-api/signals/render-callback.h>
+#include "gl-view-interface-impl.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/gl-view/gl-view-interface-impl.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
+
+namespace Dali::Toolkit
+{
+class GlView;
+
+namespace Internal
+{
+class DrawableView : public Dali::Toolkit::Internal::GlViewImpl
+{
+protected:
+ virtual ~DrawableView();
+
+public:
+ /**
+ * @copydoc Dali::Toolkit::GlView::New()
+ */
+ static Dali::Toolkit::GlView New();
+
+ /**
+ * Construct a new GlView.
+ */
+ DrawableView();
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks()
+ */
+ void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) override;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::SetResizeCallback()
+ */
+ void SetResizeCallback(CallbackBase* resizeCallback) override;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::SetGraphicsConfig()
+ */
+ bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) override;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::SetRenderingMode()
+ */
+ void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode) override;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::GetRenderingMode()
+ */
+ Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const override;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::RenderOnce()
+ */
+ void RenderOnce();
+
+private: // From Control
+ /**
+ * @copydoc Toolkit::Control::OnInitialize()
+ */
+ virtual void OnInitialize() override;
+
+ /**
+ * @copydoc Toolkit::Control::OnSceneConnection()
+ */
+ void OnSceneConnection(int depth) override;
+
+ /**
+ * @copydoc Toolkit::Control::OnSceneDisconnection()
+ */
+ void OnSceneDisconnection() override;
+
+ /**
+ * @copydoc Toolkit::Control::OnSizeSet()
+ */
+ void OnSizeSet(const Vector3& targetSize) override;
+
+private:
+ // Undefined copy constructor and assignment operators
+ DrawableView(const DrawableView& GlView);
+ DrawableView& operator=(const DrawableView& GlView);
+
+ /**
+ * Callback when the visibility of the GlView is changed
+ */
+ void OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type);
+
+ /**
+ * Callback when the visibility of the window is changed
+ */
+ void OnWindowVisibilityChanged(Dali::Window window, bool visible);
+
+ /**
+ * Adds renderer to Actor.
+ */
+ void AddRenderer();
+
+private:
+
+ bool OnRenderCallback( const RenderCallbackInput& renderCallbackInput );
+
+private:
+ Dali::Toolkit::GlView::RenderingMode mRenderingMode;
+
+ bool mDepth;
+ bool mStencil;
+ int mMSAA;
+
+ std::unique_ptr<RenderCallback> mRenderCallback;
+
+ /*
+ * Used within RenderCallback to handle the current render state
+ */
+ enum class ViewState
+ {
+ INIT,
+ RENDER,
+ TERMINATE
+ };
+
+ ViewState mCurrentViewState{ViewState::INIT}; ///< state within RenderCallback
+
+ // These callbacks are stored for GLView API compatibility
+ std::unique_ptr<CallbackBase> mOnInitCallback;
+ std::unique_ptr<CallbackBase> mOnRenderCallback;
+ std::unique_ptr<CallbackBase> mOnTerminateCallback;
+ std::unique_ptr<CallbackBase> mOnResizeCallback;
+
+ std::atomic_bool mSurfaceResized{false}; ///< Flag to invoke surface resize callback
+
+ Size mSurfaceSize{}; ///< Surface size
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_DRAWABLE_VIEW_H
{
Dali::Toolkit::GlView GlView::New(Dali::Toolkit::GlView::ColorFormat colorFormat)
{
- GlView* impl = new GlView(colorFormat);
+ auto* impl = new Dali::Toolkit::Internal::GlView(colorFormat);
Dali::Toolkit::GlView handle = Dali::Toolkit::GlView(*impl);
impl->Initialize();
return handle;
}
GlView::GlView(Dali::Toolkit::GlView::ColorFormat colorFormat)
-: Control(ControlBehaviour(ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS)),
+: Dali::Toolkit::Internal::GlViewImpl( Toolkit::GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING ),
mRenderThread(nullptr),
mNativeImageQueue(nullptr),
mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS),
// INTERNAL INCLUDES
#include <dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h>
+#include <dali-toolkit/internal/controls/gl-view/gl-view-interface-impl.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
-namespace Dali
-{
-namespace Toolkit
+
+namespace Dali::Toolkit
{
class GlView;
namespace Internal
{
-class GlView : public Dali::Toolkit::Internal::Control
+class GlView : public Dali::Toolkit::Internal::GlViewImpl
{
protected:
virtual ~GlView();
/**
* @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks()
*/
- void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+ void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) override;
/**
* @copydoc Dali::Toolkit::GlView::SetResizeCallback()
*/
- void SetResizeCallback(CallbackBase* resizeCallback);
+ void SetResizeCallback(CallbackBase* resizeCallback) override;
/**
- * @copydoc Dali::Toolkit::GlView::SetGraphisConfig()
+ * @copydoc Dali::Toolkit::GlView::SetGraphicsConfig()
*/
- bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version);
+ bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) override;
/**
* @copydoc Dali::Toolkit::GlView::SetRenderingMode()
*/
- void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode);
+ void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode) override;
/**
* @copydoc Dali::Toolkit::GlView::GetRenderingMode()
*/
- Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const;
+ Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const override;
/**
* @copydoc Dali::Toolkit::GlView::RenderOnce()
*/
- void RenderOnce();
+ void RenderOnce() override;
private: // From Control
/**
} // namespace Internal
-inline Dali::Toolkit::Internal::GlView& GetImpl(Dali::Toolkit::GlView& handle)
-{
- DALI_ASSERT_ALWAYS(handle);
- Dali::RefObject& impl = handle.GetImplementation();
- return static_cast<Dali::Toolkit::Internal::GlView&>(impl);
-}
-
-inline const Dali::Toolkit::Internal::GlView& GetImpl(const Dali::Toolkit::GlView& handle)
-{
- DALI_ASSERT_ALWAYS(handle);
- const Dali::RefObject& impl = handle.GetImplementation();
- return static_cast<const Dali::Toolkit::Internal::GlView&>(impl);
-}
-
-} // namespace Toolkit
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_GL_VIEW_H
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_GL_VIEW_IMPL_H
+#define DALI_TOOLKIT_INTERNAL_GL_VIEW_IMPL_H
+
+/*
+ * Copyright (c) 2022 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
+
+namespace Dali::Toolkit
+{
+class GlView;
+
+namespace Internal
+{
+class GlViewImpl : public Dali::Toolkit::Internal::Control
+{
+protected:
+
+ virtual ~GlViewImpl() = default;
+
+public:
+
+ /**
+ * Construct a new GlView.
+ */
+ explicit GlViewImpl( GlView::BackendMode backendMode ) :
+ Control(ControlBehaviour(0u | ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS)),
+ mBackendMode(backendMode)
+ {
+ }
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks()
+ */
+ virtual void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) = 0;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::SetResizeCallback()
+ */
+ virtual void SetResizeCallback(CallbackBase* resizeCallback) = 0;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::SetGraphisConfig()
+ */
+ virtual bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) = 0;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::SetRenderingMode()
+ */
+ virtual void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode) = 0;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::GetRenderingMode()
+ */
+ virtual Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const = 0;
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::GetBackendMode()
+ */
+ [[nodiscard]] Dali::Toolkit::GlView::BackendMode GetBackendMode() const
+ {
+ return mBackendMode;
+ }
+
+ /**
+ * @copydoc Dali::Toolkit::GlView::RenderOnce()
+ */
+ virtual void RenderOnce() = 0;
+
+private: // From Control
+ /**
+ * @copydoc Toolkit::Control::OnInitialize()
+ */
+ virtual void OnInitialize() override = 0;
+
+ /**
+ * @copydoc Toolkit::Control::OnSceneConnection()
+ */
+ virtual void OnSceneConnection(int depth) override = 0;
+
+ /**
+ * @copydoc Toolkit::Control::OnSceneDisconnection()
+ */
+ virtual void OnSceneDisconnection() override = 0;
+
+protected:
+
+ GlView::BackendMode mBackendMode { GlView::BackendMode::DEFAULT }; ///< Implementation backend mode (DirectRendering, EGL image)
+};
+
+} // namespace Internal
+
+inline Dali::Toolkit::Internal::GlViewImpl& GetImpl(Dali::Toolkit::GlView& handle)
+{
+ DALI_ASSERT_ALWAYS(handle);
+ Dali::RefObject& impl = handle.GetImplementation();
+ return static_cast<Dali::Toolkit::Internal::GlViewImpl&>(impl);
+}
+
+inline const Dali::Toolkit::Internal::GlViewImpl& GetImpl(const Dali::Toolkit::GlView& handle)
+{
+ DALI_ASSERT_ALWAYS(handle);
+ const Dali::RefObject& impl = handle.GetImplementation();
+ return static_cast<const Dali::Toolkit::Internal::GlViewImpl&>(impl);
+}
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_GL_VIEW_IMPL_H
#include <dali-toolkit/internal/controls/control/control-data-impl.h>
#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
#include <dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h>
+#include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
#include <dali-toolkit/internal/styling/style-manager-impl.h>
#include <dali-toolkit/internal/text/rendering/text-backend.h>
#include <dali-toolkit/internal/text/text-effects-style.h>
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "inputStrikethrough", MAP, INPUT_STRIKETHROUGH )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "characterSpacing", FLOAT, CHARACTER_SPACING )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "relativeLineSize", FLOAT, RELATIVE_LINE_SIZE )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "verticalAlignment", STRING, VERTICAL_ALIGNMENT )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED )
}
}
+void TextEditor::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
+{
+ DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnPropertySet index[%d]\n", index);
+
+ switch(index)
+ {
+ case DevelActor::Property::USER_INTERACTION_ENABLED:
+ {
+ const bool enabled = propertyValue.Get<bool>();
+ mController->SetUserInteractionEnabled(enabled);
+ if(mStencil)
+ {
+ float opacity = enabled ? 1.0f : mController->GetDisabledColorOpacity();
+ mStencil.SetProperty(Actor::Property::OPACITY, opacity);
+ }
+ break;
+ }
+ default:
+ {
+ Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties
+ break;
+ }
+ }
+}
+
void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
{
DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor OnRelayout\n");
notifier.ContentSelectedSignal().Connect(this, &TextEditor::OnClipboardTextSelected);
}
- mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event
+ if(IsEditable() && mController->IsUserInteractionEnabled())
+ {
+ mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event
+ }
EmitKeyInputFocusSignal(true); // Calls back into the Control hence done last.
}
mController->TapEvent(gesture.GetNumberOfTaps(), localPoint.x - padding.start, localPoint.y - padding.top);
mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top);
+ Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
+ if (keyboardFocusManager)
+ {
+ keyboardFocusManager.SetCurrentFocusActor(Self());
+ }
SetKeyInputFocus();
}
// Make sure ClearKeyInputFocus when only key is up
if(event.GetState() == KeyEvent::UP)
{
+ Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
+ if (keyboardFocusManager)
+ {
+ keyboardFocusManager.ClearFocus();
+ }
ClearKeyInputFocus();
}
void OnSceneConnection(int depth) override;
/**
+ * @copydoc Control::OnPropertySet()
+ */
+ void OnPropertySet(Property::Index index, const Property::Value& propertyValue) override;
+
+ /**
* @copydoc Dali::CustomActorImpl::OnKeyEvent(const KeyEvent&)
*/
bool OnKeyEvent(const KeyEvent& event) override;
}
break;
}
+ case Toolkit::DevelTextEditor::Property::VERTICAL_ALIGNMENT:
+ {
+ Toolkit::Text::VerticalAlignment::Type alignment(static_cast<Text::VerticalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+ if(Text::GetVerticalAlignmentEnumeration(value, alignment))
+ {
+ impl.mController->SetVerticalAlignment(alignment);
+ DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p VERTICAL_ALIGNMENT %d\n", impl.mController.Get(), alignment);
+ }
+ break;
+ }
case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
{
const float threshold = value.Get<float>();
}
break;
}
+ case Toolkit::DevelTextEditor::Property::VERTICAL_ALIGNMENT:
+ {
+ const char* name = Text::GetVerticalAlignmentString(impl.mController->GetVerticalAlignment());
+
+ if(name)
+ {
+ value = std::string(name);
+ }
+ break;
+ }
case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
{
value = impl.mDecorator->GetScrollThreshold();
#include <dali-toolkit/devel-api/text/rendering-backend.h>
#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
#include <dali-toolkit/internal/controls/text-controls/text-field-property-handler.h>
+#include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
#include <dali-toolkit/internal/styling/style-manager-impl.h>
#include <dali-toolkit/internal/text/rendering/text-backend.h>
#include <dali-toolkit/internal/text/text-effects-style.h>
}
}
+void TextField::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
+{
+ DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnPropertySet index[%d]\n", index);
+
+ switch(index)
+ {
+ case DevelActor::Property::USER_INTERACTION_ENABLED:
+ {
+ const bool enabled = propertyValue.Get<bool>();
+ mController->SetUserInteractionEnabled(enabled);
+ if(mStencil)
+ {
+ float opacity = enabled ? 1.0f : mController->GetDisabledColorOpacity();
+ mStencil.SetProperty(Actor::Property::OPACITY, opacity);
+ }
+ break;
+ }
+ default:
+ {
+ Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties
+ break;
+ }
+ }
+}
+
void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
{
DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField OnRelayout\n");
notifier.ContentSelectedSignal().Connect(this, &TextField::OnClipboardTextSelected);
}
- mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event
+ if(IsEditable() && mController->IsUserInteractionEnabled())
+ {
+ mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event
+ }
EmitKeyInputFocusSignal(true); // Calls back into the Control hence done last.
}
mController->TapEvent(gesture.GetNumberOfTaps(), localPoint.x - padding.start, localPoint.y - padding.top);
mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top);
+ Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
+ if (keyboardFocusManager)
+ {
+ keyboardFocusManager.SetCurrentFocusActor(Self());
+ }
SetKeyInputFocus();
}
// Make sure ClearKeyInputFocus when only key is up
if(event.GetState() == KeyEvent::UP)
{
+ Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
+ if (keyboardFocusManager)
+ {
+ keyboardFocusManager.ClearFocus();
+ }
ClearKeyInputFocus();
}
void OnSceneConnection(int depth) override;
/**
+ * @copydoc Control::OnPropertySet()
+ */
+ void OnPropertySet(Property::Index index, const Property::Value& propertyValue) override;
+
+ /**
* @copydoc Dali::CustomActorImpl::OnKeyEvent(const KeyEvent&)
*/
bool OnKeyEvent(const KeyEvent& event) override;
#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/text-controls/text-selection-popup-property-handler.h>
#include <dali-toolkit/internal/helpers/color-conversion.h>
#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
if(selectionPopup)
{
- TextSelectionPopup& impl(GetImpl(selectionPopup));
-
- switch(index)
- {
- case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
- {
- impl.SetDimensionToCustomise(POPUP_MAXIMUM_SIZE, value.Get<Vector2>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
- {
- impl.SetDimensionToCustomise(OPTION_MAXIMUM_SIZE, value.Get<Vector2>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
- {
- impl.SetDimensionToCustomise(OPTION_MINIMUM_SIZE, value.Get<Vector2>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
- {
- impl.SetDimensionToCustomise(OPTION_DIVIDER_SIZE, value.Get<Vector2>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_PADDING:
- {
- Vector4 padding(value.Get<Vector4>());
- impl.SetOptionDividerPadding(Padding(padding.x, padding.y, padding.z, padding.w));
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
- {
- impl.SetButtonImage(Toolkit::TextSelectionPopup::CLIPBOARD, value.Get<std::string>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
- {
- impl.SetButtonImage(Toolkit::TextSelectionPopup::CUT, value.Get<std::string>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
- {
- impl.SetButtonImage(Toolkit::TextSelectionPopup::COPY, value.Get<std::string>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
- {
- impl.SetButtonImage(Toolkit::TextSelectionPopup::PASTE, value.Get<std::string>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
- {
- impl.SetButtonImage(Toolkit::TextSelectionPopup::SELECT, value.Get<std::string>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
- {
- impl.SetButtonImage(Toolkit::TextSelectionPopup::SELECT_ALL, value.Get<std::string>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_DIVIDER_COLOR:
- {
- impl.mDividerColor = value.Get<Vector4>();
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_ICON_COLOR:
- {
- impl.mIconColor = value.Get<Vector4>();
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_COLOR:
- {
- impl.mPressedColor = value.Get<Vector4>();
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
- {
- impl.SetPressedImage(value.Get<std::string>());
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
- {
- impl.mFadeInDuration = value.Get<float>();
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
- {
- impl.mFadeOutDuration = value.Get<float>();
- break;
- }
- case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
- {
- Property::Map map = value.Get<Property::Map>();
- impl.CreateBackgroundBorder(map);
- break;
- }
- } // switch
- } // TextSelectionPopup
+ PropertyHandler::SetProperty(selectionPopup, index, value);
+ }
}
Property::Value TextSelectionPopup::GetProperty(BaseObject* object, Property::Index index)
if(selectionPopup)
{
- TextSelectionPopup& impl(GetImpl(selectionPopup));
-
- switch(index)
- {
- case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
- {
- value = impl.GetDimensionToCustomise(POPUP_MAXIMUM_SIZE);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
- {
- value = impl.GetDimensionToCustomise(OPTION_MAXIMUM_SIZE);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
- {
- value = impl.GetDimensionToCustomise(OPTION_MINIMUM_SIZE);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
- {
- value = impl.GetDimensionToCustomise(OPTION_DIVIDER_SIZE);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_PADDING:
- {
- Padding padding = impl.GetOptionDividerPadding();
- value = Vector4(padding.left, padding.right, padding.top, padding.bottom);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
- {
- value = impl.GetButtonImage(Toolkit::TextSelectionPopup::CLIPBOARD);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
- {
- value = impl.GetButtonImage(Toolkit::TextSelectionPopup::CUT);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
- {
- value = impl.GetButtonImage(Toolkit::TextSelectionPopup::COPY);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
- {
- value = impl.GetButtonImage(Toolkit::TextSelectionPopup::PASTE);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
- {
- value = impl.GetButtonImage(Toolkit::TextSelectionPopup::SELECT);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
- {
- value = impl.GetButtonImage(Toolkit::TextSelectionPopup::SELECT_ALL);
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
- {
- value = impl.GetPressedImage();
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
- {
- value = impl.mFadeInDuration;
- break;
- }
- case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
- {
- value = impl.mFadeOutDuration;
- break;
- }
- case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
- {
- Property::Map map;
- Toolkit::Visual::Base visual = DevelControl::GetVisual(impl, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER);
- if(visual)
- {
- visual.CreatePropertyMap(map);
- }
- value = map;
- break;
- }
- } // switch
+ value = PropertyHandler::GetProperty(selectionPopup, index);
}
return value;
}
virtual ~TextSelectionPopup();
protected:
+ struct PropertyHandler;
+
class TextSelectionPopupAccessible : public DevelControl::ControlAccessible
{
public:
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit/internal/controls/text-controls/text-selection-popup-property-handler.h>
+#include <dali/integration-api/debug.h>
+
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gLogFilter;
+#endif
+
+namespace Dali::Toolkit::Internal
+{
+void TextSelectionPopup::PropertyHandler::SetProperty(Toolkit::TextSelectionPopup selectionPopup, Property::Index index, const Property::Value& value)
+{
+ TextSelectionPopup& impl(GetImpl(selectionPopup));
+
+ switch(index)
+ {
+ case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
+ {
+ impl.SetDimensionToCustomise(POPUP_MAXIMUM_SIZE, value.Get<Vector2>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
+ {
+ impl.SetDimensionToCustomise(OPTION_MAXIMUM_SIZE, value.Get<Vector2>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
+ {
+ impl.SetDimensionToCustomise(OPTION_MINIMUM_SIZE, value.Get<Vector2>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
+ {
+ impl.SetDimensionToCustomise(OPTION_DIVIDER_SIZE, value.Get<Vector2>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_PADDING:
+ {
+ Vector4 padding(value.Get<Vector4>());
+ impl.SetOptionDividerPadding(Padding(padding.x, padding.y, padding.z, padding.w));
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
+ {
+ impl.SetButtonImage(Toolkit::TextSelectionPopup::CLIPBOARD, value.Get<std::string>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
+ {
+ impl.SetButtonImage(Toolkit::TextSelectionPopup::CUT, value.Get<std::string>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
+ {
+ impl.SetButtonImage(Toolkit::TextSelectionPopup::COPY, value.Get<std::string>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
+ {
+ impl.SetButtonImage(Toolkit::TextSelectionPopup::PASTE, value.Get<std::string>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
+ {
+ impl.SetButtonImage(Toolkit::TextSelectionPopup::SELECT, value.Get<std::string>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
+ {
+ impl.SetButtonImage(Toolkit::TextSelectionPopup::SELECT_ALL, value.Get<std::string>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_DIVIDER_COLOR:
+ {
+ impl.mDividerColor = value.Get<Vector4>();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_ICON_COLOR:
+ {
+ impl.mIconColor = value.Get<Vector4>();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_COLOR:
+ {
+ impl.mPressedColor = value.Get<Vector4>();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
+ {
+ impl.SetPressedImage(value.Get<std::string>());
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
+ {
+ impl.mFadeInDuration = value.Get<float>();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
+ {
+ impl.mFadeOutDuration = value.Get<float>();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
+ {
+ Property::Map map = value.Get<Property::Map>();
+ impl.CreateBackgroundBorder(map);
+ break;
+ }
+ }
+}
+
+Property::Value TextSelectionPopup::PropertyHandler::GetProperty(Toolkit::TextSelectionPopup selectionPopup, Property::Index index)
+{
+ Property::Value value;
+ TextSelectionPopup& impl(GetImpl(selectionPopup));
+
+ switch(index)
+ {
+ case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
+ {
+ value = impl.GetDimensionToCustomise(POPUP_MAXIMUM_SIZE);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
+ {
+ value = impl.GetDimensionToCustomise(OPTION_MAXIMUM_SIZE);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
+ {
+ value = impl.GetDimensionToCustomise(OPTION_MINIMUM_SIZE);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
+ {
+ value = impl.GetDimensionToCustomise(OPTION_DIVIDER_SIZE);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_PADDING:
+ {
+ Padding padding = impl.GetOptionDividerPadding();
+ value = Vector4(padding.left, padding.right, padding.top, padding.bottom);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
+ {
+ value = impl.GetButtonImage(Toolkit::TextSelectionPopup::CLIPBOARD);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
+ {
+ value = impl.GetButtonImage(Toolkit::TextSelectionPopup::CUT);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
+ {
+ value = impl.GetButtonImage(Toolkit::TextSelectionPopup::COPY);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
+ {
+ value = impl.GetButtonImage(Toolkit::TextSelectionPopup::PASTE);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
+ {
+ value = impl.GetButtonImage(Toolkit::TextSelectionPopup::SELECT);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
+ {
+ value = impl.GetButtonImage(Toolkit::TextSelectionPopup::SELECT_ALL);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_DIVIDER_COLOR:
+ {
+ value = impl.mDividerColor;
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_ICON_COLOR:
+ {
+ value = impl.mIconColor;
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_COLOR:
+ {
+ value = impl.mPressedColor;
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
+ {
+ value = impl.GetPressedImage();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
+ {
+ value = impl.mFadeInDuration;
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
+ {
+ value = impl.mFadeOutDuration;
+ break;
+ }
+ case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
+ {
+ Property::Map map;
+ Toolkit::Visual::Base visual = DevelControl::GetVisual(impl, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER);
+ if(visual)
+ {
+ visual.CreatePropertyMap(map);
+ }
+ value = map;
+ break;
+ }
+ }
+
+ return value;
+}
+
+} // namespace Dali::Toolkit::Internal
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_POPUP_PROPERTY_HANDLER_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_POPUP_PROPERTY_HANDLER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h>
+
+namespace Dali::Toolkit::Internal
+{
+/**
+ * Class to manage properties for the TextSelectionPopup
+ */
+struct TextSelectionPopup::PropertyHandler
+{
+ /**
+ * Set properties on the text selection popup
+ *
+ * @param[in] selectionPopup The handle for the text selection popup
+ * @param[in] index The property index of the property to set
+ * @param[in] value The value to set
+ */
+ static void SetProperty(Toolkit::TextSelectionPopup selectionPopup, Property::Index index, const Property::Value& value);
+
+ /**
+ * Get properties from the text selection popup
+ *
+ * @param[in] selectionPopup The handle for the text selection popup
+ * @param[in] index The property index of the property to set
+ * @return the value
+ */
+ static Property::Value GetProperty(Toolkit::TextSelectionPopup selectionPopup, Property::Index index);
+};
+
+} // namespace Dali::Toolkit::Internal
+
+#endif //DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_POPUP_PROPERTY_HANDLER_H
mWebSettings = std::unique_ptr<Dali::Toolkit::WebSettings>(new WebSettings(mWebEngine.GetSettings()));
mWebBackForwardList = std::unique_ptr<Dali::Toolkit::WebBackForwardList>(new WebBackForwardList(mWebEngine.GetBackForwardList()));
}
+
+ self.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::FILLER);
+}
+
+DevelControl::ControlAccessible* WebView::CreateAccessibleObject()
+{
+ return new WebViewAccessible(Self(), mWebEngine);
}
Dali::Toolkit::WebSettings* WebView::GetSettings() const
return mWebEngine ? mWebEngine.SetVisibility(visible) : false;
}
+WebView::WebViewAccessible::WebViewAccessible(Dali::Actor self, Dali::WebEngine& webEngine)
+: ControlAccessible(self), mRemoteChild{}, mWebEngine{webEngine}
+{
+ Dali::Accessibility::Bridge::EnabledSignal().Connect(this, &WebViewAccessible::OnAccessibilityEnabled);
+ Dali::Accessibility::Bridge::DisabledSignal().Connect(this, &WebViewAccessible::OnAccessibilityDisabled);
+
+ if(Dali::Accessibility::IsUp())
+ {
+ OnAccessibilityEnabled();
+ }
+ else
+ {
+ OnAccessibilityDisabled();
+ }
+}
+
+void WebView::WebViewAccessible::DoGetChildren(std::vector<Dali::Accessibility::Accessible*>& children)
+{
+ if(mRemoteChild.GetAddress())
+ {
+ children.push_back(&mRemoteChild);
+ }
+}
+
+void WebView::WebViewAccessible::OnAccessibilityEnabled()
+{
+ if(!mWebEngine)
+ {
+ return;
+ }
+
+ mWebEngine.ActivateAccessibility(true);
+ SetRemoteChildAddress(mWebEngine.GetAccessibilityAddress());
+}
+
+void WebView::WebViewAccessible::OnAccessibilityDisabled()
+{
+ if(!mWebEngine)
+ {
+ return;
+ }
+
+ SetRemoteChildAddress({});
+ mWebEngine.ActivateAccessibility(false);
+}
+
+void WebView::WebViewAccessible::SetRemoteChildAddress(Dali::Accessibility::Address address)
+{
+ mRemoteChild.SetAddress(std::move(address));
+ OnChildrenChanged();
+}
+
#undef GET_ENUM_STRING
#undef GET_ENUM_VALUE
// EXTERNAL INCLUDES
#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/adaptor-framework/proxy-accessible.h>
#include <dali/devel-api/adaptor-framework/web-engine.h>
#include <dali/public-api/images/image-operations.h>
#include <dali/public-api/object/property-notification.h>
#include <memory>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-accessible.h>
#include <dali-toolkit/devel-api/controls/web-view/web-view.h>
#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
void OnInitialize() override;
/**
+ * @copydoc Toolkit::Internal::Control::CreateAccessibleObject()
+ */
+ DevelControl::ControlAccessible* CreateAccessibleObject() override;
+
+ /**
* @copydoc Toolkit::Control::GetNaturalSize
*/
Vector3 GetNaturalSize() override;
*/
void OnScreenshotCaptured(Dali::PixelData pixel);
+protected:
+ class WebViewAccessible : public DevelControl::ControlAccessible
+ {
+ public:
+ WebViewAccessible() = delete;
+
+ WebViewAccessible(Dali::Actor self, Dali::WebEngine& webEngine);
+
+ protected:
+ /**
+ * @copydoc Dali::Accessibility::ActorAccessible::DoGetChildren()
+ */
+ void DoGetChildren(std::vector<Dali::Accessibility::Accessible*>& children) override;
+
+ private:
+ void OnAccessibilityEnabled();
+ void OnAccessibilityDisabled();
+ void SetRemoteChildAddress(Dali::Accessibility::Address address);
+
+ Dali::Accessibility::ProxyAccessible mRemoteChild;
+ Dali::WebEngine& mWebEngine;
+ };
+
private:
Dali::Toolkit::Visual::Base mVisual;
Dali::Size mWebViewSize;
${toolkit_src_dir}/controls/text-controls/text-field-property-handler.cpp
${toolkit_src_dir}/controls/text-controls/text-label-impl.cpp
${toolkit_src_dir}/controls/text-controls/text-selection-popup-impl.cpp
+ ${toolkit_src_dir}/controls/text-controls/text-selection-popup-property-handler.cpp
${toolkit_src_dir}/controls/text-controls/text-selection-toolbar-impl.cpp
${toolkit_src_dir}/controls/tool-bar/tool-bar-impl.cpp
${toolkit_src_dir}/controls/tooltip/tooltip.cpp
${toolkit_src_dir}/controls/video-view/video-view-impl.cpp
${toolkit_src_dir}/controls/web-view/web-view-impl.cpp
${toolkit_src_dir}/controls/camera-view/camera-view-impl.cpp
+ ${toolkit_src_dir}/controls/gl-view/drawable-view-impl.cpp
${toolkit_src_dir}/controls/gl-view/gl-view-impl.cpp
${toolkit_src_dir}/controls/gl-view/gl-view-render-thread.cpp
${toolkit_src_dir}/accessibility-manager/accessibility-manager-impl.cpp
}
}
- if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+ if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
{
Integration::SceneHolder currentWindow = Integration::SceneHolder::Get(actor);
}
// Check whether the actor is in the stage and is keyboard focusable.
- if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+ if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
{
if((mIsFocusIndicatorShown == SHOW) && (mEnableFocusIndicator == ENABLE))
{
actor.Add(GetFocusIndicatorActor());
}
- // Send notification for the change of focus actor
- if(!mFocusChangedSignal.Empty())
- {
- mFocusChangedSignal.Emit(currentFocusedActor, actor);
- }
Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor);
if(currentlyFocusedControl)
currentlyFocusedControl.ClearKeyInputFocus();
}
- DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__);
-
// Save the current focused actor
mCurrentFocusActor = actor;
mFocusHistory.erase(beginPos);
}
+ // Send notification for the change of focus actor
+ if(!mFocusChangedSignal.Empty())
+ {
+ mFocusChangedSignal.Emit(currentFocusedActor, actor);
+ }
DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__);
success = true;
}
}
}
- if(nextFocusableActor && nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
+ if(nextFocusableActor && nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && nextFocusableActor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED))
{
// Whether the next focusable actor is a layout control
if(IsLayoutControl(nextFocusableActor))
Actor nextFocusableActor = GetImplementation(control).GetNextKeyboardFocusableActor(actor, direction, mFocusGroupLoopEnabled);
if(nextFocusableActor)
{
- if(!nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
+ if(!(nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) || nextFocusableActor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED)))
{
// If the actor is not focusable, ask the same layout control for the next actor to focus
return DoMoveFocusWithinLayoutControl(control, nextFocusableActor, direction);
mIsWaitingKeyboardFocusChangeCommit = false;
}
- if(committedFocusActor && committedFocusActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
+ if(committedFocusActor && committedFocusActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && committedFocusActor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED))
{
// Whether the commited focusable actor is a layout control
if(IsLayoutControl(committedFocusActor))
void KeyboardFocusManager::ClearFocus()
{
+ ClearFocusIndicator();
Actor actor = GetCurrentFocusActor();
if(actor)
{
- if(mFocusIndicatorActor)
- {
- actor.Remove(mFocusIndicatorActor);
- }
-
// Send notification for the change of focus actor
if(!mFocusChangedSignal.Empty())
{
currentlyFocusedControl.ClearKeyInputFocus();
}
}
-
mCurrentFocusActor.Reset();
+}
+
+void KeyboardFocusManager::ClearFocusIndicator()
+{
+ Actor actor = GetCurrentFocusActor();
+ if(actor)
+ {
+ if(mFocusIndicatorActor)
+ {
+ actor.Remove(mFocusIndicatorActor);
+ }
+ }
mIsFocusIndicatorShown = (mAlwaysShowIndicator == ALWAYS_SHOW) ? SHOW : HIDE;
}
// We only do this on a Down event, otherwise the clear action may override a manually focused actor.
if(((touch.GetPointCount() < 1) || (touch.GetState(0) == PointState::DOWN)))
{
- // If mClearFocusOnTouch is false, do not clear the focus even if user touch the screen.
- if(mClearFocusOnTouch)
+ // If you touch the currently focused actor again, you don't need to do SetCurrentFocusActor again.
+ Actor hitActor = touch.GetHitActor(0);
+ if(hitActor && hitActor == GetCurrentFocusActor())
{
- ClearFocus();
+ return;
}
-
// If KEYBOARD_FOCUSABLE and TOUCH_FOCUSABLE is true, set focus actor
- Actor hitActor = touch.GetHitActor(0);
if(hitActor && hitActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && hitActor.GetProperty<bool>(DevelActor::Property::TOUCH_FOCUSABLE))
{
+ // If mClearFocusOnTouch is false, do not clear the focus
+ if(mClearFocusOnTouch)
+ {
+ ClearFocus();
+ }
SetCurrentFocusActor(hitActor);
}
+ else
+ {
+ // If mClearFocusOnTouch is false, do not clear the focus indicator even if user touch the screen.
+ if(mClearFocusOnTouch)
+ {
+ ClearFocusIndicator();
+ }
+ }
}
}
*/
bool EmitCustomWheelSignals(Actor actor, const WheelEvent& event);
+ /**
+ * Clear the focus indicator actor.
+ */
+ void ClearFocusIndicator();
+
private:
// Undefined
KeyboardFocusManager(const KeyboardFocusManager&);
BoundedParagraphRun()
: characterRun{},
horizontalAlignment(Text::HorizontalAlignment::BEGIN),
- horizontalAlignmentDefined{false}
+ relativeLineSize(1),
+ horizontalAlignmentDefined{false},
+ relativeLineSizeDefined(false)
{
}
CharacterRun characterRun; ///< The initial character index within the whole text and the number of characters of the run.
Text::HorizontalAlignment::Type horizontalAlignment; ///< The paragraph horizontal alignment. Values "BEGIN" "CENTER" "END".
+ float relativeLineSize; ///< The relative line height to be used for this paragaraph.
bool horizontalAlignmentDefined : 1; ///< Whether the horizontal alignment is defined.
+ bool relativeLineSizeDefined : 1; ///< Whether the relative line height is defined for this paragraph.
};
} // namespace Text
void Decorator::SetEditable(bool editable)
{
mImpl->mHidePrimaryCursorAndGrabHandle = !editable;
+ // If editable is false, all decorators should be disabled.
+ if(!editable)
+ {
+ if(IsHighlightActive())
+ {
+ SetHighlightActive(false);
+ }
+ if(IsHandleActive(LEFT_SELECTION_HANDLE))
+ {
+ SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ }
+ if(IsHandleActive(RIGHT_SELECTION_HANDLE))
+ {
+ SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ }
+ if(IsPopupActive())
+ {
+ SetPopupActive(false);
+ }
+ }
+
mImpl->Relayout(mImpl->mControlSize);
}
/** Handles **/
glyphIndexInSecondHalfLine{0u},
characterIndexInSecondHalfLine{0u},
numberOfGlyphsInSecondHalfLine{0u},
- numberOfCharactersInSecondHalfLine{0u}
+ numberOfCharactersInSecondHalfLine{0u},
+ relativeLineSize{1.0f}
{
}
characterIndexInSecondHalfLine = 0u;
numberOfGlyphsInSecondHalfLine = 0u;
numberOfCharactersInSecondHalfLine = 0u;
+ relativeLineSize = 1.0f;
}
GlyphIndex glyphIndex; ///< Index of the first glyph to be laid-out.
CharacterIndex characterIndexInSecondHalfLine; ///< Index of the first character to be laid-out for the second half of line.
Length numberOfGlyphsInSecondHalfLine; ///< The number of glyph which fit in one line for the second half of line.
Length numberOfCharactersInSecondHalfLine; ///< The number of characters which fit in one line for the second half of line.
+
+ float relativeLineSize; ///< The relative line size to be applied for this line.
};
struct LayoutBidiParameters
* @brief get the line spacing.
*
* @param[in] textSize The text size.
+ * @param[in] relativeLineSize The relative line size to be applied.
* @return the line spacing value.
*/
- float GetLineSpacing(float textSize)
+ float GetLineSpacing(float textSize, float relativeLineSize)
{
float lineSpacing;
float relTextSize;
lineSpacing += mDefaultLineSpacing;
//subtract line spcaing if relativeLineSize < 1 & larger than min height
- relTextSize = textSize * mRelativeLineSize;
+ relTextSize = textSize * relativeLineSize;
if(relTextSize > mDefaultLineSize)
{
- if(mRelativeLineSize < 1)
+ if(relativeLineSize < 1)
{
//subtract the difference (always will be positive)
lineSpacing -= (textSize - relTextSize);
// Sets the minimum descender.
lineLayout.descender = std::min(lineLayout.descender, fontMetrics.descender);
- lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender);
+ lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender, lineLayout.relativeLineSize);
}
/**
// It needs to add as well space for the cursor if the text is in edit mode and extra space in case the text is outlined.
tmpLineLayout.penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
+ tmpLineLayout.relativeLineSize = lineLayout.relativeLineSize;
+
// Calculate the line height if there is no characters.
FontId lastFontId = glyphMetrics.fontId;
UpdateLineHeight(glyphMetrics, tmpLineLayout);
LineRun* lineRun = nullptr;
LineLayout ellipsisLayout;
+
+ ellipsisLayout.relativeLineSize = layout.relativeLineSize;
+
if(0u != numberOfLines)
{
// Get the last line and layout it again with the 'completelyFill' flag to true.
lineRun.direction = layout.direction;
lineRun.ellipsis = false;
- lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender);
+ lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, layout.relativeLineSize);
// Update the actual size.
if(lineRun.width > layoutSize.width)
lineRun.direction = LTR;
lineRun.ellipsis = false;
- lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender);
+ BoundedParagraphRun currentParagraphRun;
+ LineLayout tempLineLayout;
+ (GetBoundedParagraph(layoutParameters.textModel->GetBoundedParagraphRuns(), characterIndex, currentParagraphRun) ? SetRelativeLineSize(¤tParagraphRun, tempLineLayout) : SetRelativeLineSize(nullptr, tempLineLayout));
+
+ lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, tempLineLayout.relativeLineSize);
layoutSize.height += GetLineHeight(lineRun, true);
}
}
}
+ /**
+ * @brief Sets the relative line size for the LineLayout
+ *
+ * @param[in] currentParagraphRun Contains the bounded paragraph for this line layout.
+ * @param[in,out] lineLayout The line layout to be updated.
+ */
+ void SetRelativeLineSize(BoundedParagraphRun* currentParagraphRun, LineLayout& lineLayout)
+ {
+ lineLayout.relativeLineSize = mRelativeLineSize;
+
+ if(currentParagraphRun != nullptr && currentParagraphRun->relativeLineSizeDefined)
+ {
+ lineLayout.relativeLineSize = currentParagraphRun->relativeLineSize;
+ }
+ }
+
+ /**
+ * @brief Get the bounded paragraph for the characterIndex if exists.
+ *
+ * @param[in] boundedParagraphRuns The bounded paragraph list to search in.
+ * @param[in] characterIndex The character index to get bounded paragraph for.
+ * @param[out] currentParagraphRun Contains the bounded paragraph if found for the characterIndex.
+ *
+ * @return returns true if a bounded paragraph was found.
+ */
+ bool GetBoundedParagraph(const Vector<BoundedParagraphRun> boundedParagraphRuns, CharacterIndex characterIndex, BoundedParagraphRun& currentParagraphRun)
+ {
+ for(Vector<BoundedParagraphRun>::Iterator it = boundedParagraphRuns.Begin(),
+ endIt = boundedParagraphRuns.End();
+ it != endIt;
+ ++it)
+ {
+ BoundedParagraphRun& tempParagraphRun = *it;
+
+ if(characterIndex >= tempParagraphRun.characterRun.characterIndex &&
+ characterIndex < (tempParagraphRun.characterRun.characterIndex + tempParagraphRun.characterRun.numberOfCharacters))
+ {
+ currentParagraphRun = tempParagraphRun;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
bool LayoutText(Parameters& layoutParameters,
Size& layoutSize,
bool elideTextEnabled,
layoutParameters.textModel->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(0u);
layoutParameters.textModel->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(0u);
- Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
+ Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
+ const Vector<BoundedParagraphRun>& boundedParagraphRuns = layoutParameters.textModel->GetBoundedParagraphRuns();
if(0u == layoutParameters.numberOfGlyphs)
{
// Retrieve BiDi info.
const bool hasBidiParagraphs = !layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo.Empty();
- const CharacterIndex* const glyphsToCharactersBuffer = hasBidiParagraphs ? layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin() : nullptr;
+ const CharacterIndex* const glyphsToCharactersBuffer = layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin();
const Vector<BidirectionalParagraphInfoRun>& bidirectionalParagraphsInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo;
const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
LineLayout layout;
layout.direction = layoutBidiParameters.paragraphDirection;
layout.glyphIndex = index;
+
+ BoundedParagraphRun currentParagraphRun;
+ (GetBoundedParagraph(boundedParagraphRuns, *(glyphsToCharactersBuffer + index), currentParagraphRun) ? SetRelativeLineSize(¤tParagraphRun, layout) : SetRelativeLineSize(nullptr, layout));
+
GetLineLayoutForBox(layoutParameters,
layoutBidiParameters,
layout,
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " number of characters %d\n", layout.numberOfCharacters);
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " length %f\n", layout.length);
+ CharacterIndex lastCharacterInParagraph = currentParagraphRun.characterRun.characterIndex + currentParagraphRun.characterRun.numberOfCharacters - 1;
+
+ //check if this is the last line in paragraph, if false we should use the default relative line size (the one set using the property)
+ if(lastCharacterInParagraph >= layout.characterIndex && lastCharacterInParagraph < layout.characterIndex+layout.numberOfCharacters)
+ {
+ layout.relativeLineSize = mRelativeLineSize;
+ }
+
if(0u == layout.numberOfGlyphs + layout.numberOfGlyphsInSecondHalfLine)
{
// The width is too small and no characters are laid-out.
}
// Updates the vertical pen's position.
- penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender);
+ penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender, layout.relativeLineSize);
// Increase the glyph index.
index = nextIndex;
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/anchor.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
namespace Dali
{
{
namespace Text
{
-namespace
-{
-const std::string XHTML_HREF_ATTRIBUTE("href");
-} // namespace
-
void ProcessAnchor(const Tag& tag, Anchor& anchor)
{
anchor.href = nullptr;
for(auto&& attribute : tag.attributes)
{
- if(TokenComparison(XHTML_HREF_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::HREF, attribute.nameBuffer, attribute.nameLength))
{
Length hrefLength = attribute.valueLength + 1;
anchor.href = new char[hrefLength];
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/color-run.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
namespace Dali
{
{
namespace Text
{
-namespace
-{
-const std::string XHTML_COLOR_ATTRIBUTE("color");
-} // namespace
-
void ProcessBackground(const Tag& tag, ColorRun& colorRun)
{
for(auto&& attribute : tag.attributes)
{
- if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::BACKGROUND_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
{
ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
}
#include <dali-toolkit/internal/text/character-spacing-character-run.h>
#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
namespace Dali
{
{
namespace Text
{
-namespace
-{
-const std::string XHTML_VALUE_ATTRIBUTE("value");
-
-} // namespace
-
void ProcessValueAttribute(const Attribute& attribute, CharacterSpacingCharacterRun& characterSpacingCharacterRun)
{
characterSpacingCharacterRun.value = ProcessFloatAttribute(attribute);
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::CHARACTER_SPACING_ATTRIBUTES::VALUE, attribute.nameBuffer, attribute.nameLength))
{
ProcessValueAttribute(attribute, characterSpacingCharacterRun);
}
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/color-run.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
namespace Dali
{
{
namespace Text
{
-namespace
-{
-const std::string XHTML_VALUE_ATTRIBUTE("value");
-}
-
void ProcessColor(const Attribute& attribute, ColorRun& colorRun)
{
ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
++it)
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::COLOR_ATTRIBUTES::VALUE, attribute.nameBuffer, attribute.nameLength))
{
ProcessColor(attribute, colorRun);
}
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/embedded-item.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
namespace Dali
{
{
namespace
{
-const std::string XHTML_URL_ATTRIBUTE("url");
-const std::string XHTML_WIDTH_ATTRIBUTE("width");
-const std::string XHTML_HEIGHT_ATTRIBUTE("height");
-const std::string XHTML_COLOR_BLENDING_ATTRIBUTE("color-blending");
-
const std::string NONE("none");
const std::string MULTIPLY("multiply");
} // namespace
++it)
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_URL_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::URL, attribute.nameBuffer, attribute.nameLength))
{
embeddedItem.urlLength = attribute.valueLength;
embeddedItem.url = new char[embeddedItem.urlLength];
memcpy(embeddedItem.url, attribute.valueBuffer, embeddedItem.urlLength);
// The memory is freed when the font run is removed from the logical model.
}
- else if(TokenComparison(XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::WIDTH, attribute.nameBuffer, attribute.nameLength))
{
embeddedItem.width = StringToUint(attribute.valueBuffer);
}
- else if(TokenComparison(XHTML_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
{
embeddedItem.height = StringToUint(attribute.valueBuffer);
}
- else if(TokenComparison(XHTML_COLOR_BLENDING_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::COLOR_BLENDING, attribute.nameBuffer, attribute.nameLength))
{
if(TokenComparison(MULTIPLY, attribute.valueBuffer, attribute.valueLength))
{
#include <dali-toolkit/internal/text/font-description-run.h>
#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
#include <dali-toolkit/internal/text/text-font-style.h>
namespace Dali
{
namespace
{
-const std::string XHTML_FAMILY_ATTRIBUTE("family");
-const std::string XHTML_SIZE_ATTRIBUTE("size");
-const std::string XHTML_WEIGHT_ATTRIBUTE("weight");
-const std::string XHTML_WIDTH_ATTRIBUTE("width");
-const std::string XHTML_SLANT_ATTRIBUTE("slant");
-
const std::string FONT_PREFIX("font-");
const unsigned int FONT_PREFIX_LENGTH = 5u;
const unsigned int MIN_FONT_ATTRIBUTE_SIZE = 4u; ///< The minimum length of any of the possible 'weight', 'width' , 'slant' or 'size' values.
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_FAMILY_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::FONT_ATTRIBUTES::FAMILY, attribute.nameBuffer, attribute.nameLength))
{
ProcessFontFamily(attribute, fontRun);
}
- else if(TokenComparison(XHTML_SIZE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::SIZE, attribute.nameBuffer, attribute.nameLength))
{
ProcessFontSize(attribute, fontRun);
}
- else if(TokenComparison(XHTML_WEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::WEIGHT, attribute.nameBuffer, attribute.nameLength))
{
ProcessFontWeight(attribute, fontRun);
}
- else if(TokenComparison(XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::WIDTH, attribute.nameBuffer, attribute.nameLength))
{
ProcessFontWidth(attribute, fontRun);
}
- else if(TokenComparison(XHTML_SLANT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::SLANT, attribute.nameBuffer, attribute.nameLength))
{
ProcessFontSlant(attribute, fontRun);
}
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/bounded-paragraph-run.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
namespace Dali
{
{
namespace Text
{
-namespace
-{
-const std::string XHTML_ALIGN_ATTRIBUTE("align");
-}
-
void ProcessHorizontalAlignment(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun)
{
boundedParagraphRun.horizontalAlignmentDefined = HorizontalAlignmentTypeStringToTypeValue(attribute.valueBuffer,
boundedParagraphRun.horizontalAlignment);
}
+void ProcessRelativeLineHeight(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun)
+{
+ boundedParagraphRun.relativeLineSize = StringToFloat(attribute.valueBuffer);
+ boundedParagraphRun.relativeLineSizeDefined = true;
+}
+
void ProcessAttributesOfParagraphTag(const Tag& tag, BoundedParagraphRun& boundedParagraphRun)
{
// By default the align attribute is not defined until it's parsed.
++it)
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_ALIGN_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::PARAGRAPH_ATTRIBUTES::ALIGN, attribute.nameBuffer, attribute.nameLength))
{
ProcessHorizontalAlignment(attribute, boundedParagraphRun);
}
+ else if(TokenComparison(MARKUP::PARAGRAPH_ATTRIBUTES::RELATIVE_LINE_HEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessRelativeLineHeight(attribute, boundedParagraphRun);
+ }
}
}
-
} // namespace Text
} // namespace Toolkit
*/
void ProcessAttributesOfParagraphTag(const Tag& tag, BoundedParagraphRun& boundedParagraphRun);
+/**
+ * @brief Retrieves the relative line height value from the paragraph tag and sets it to the bounded paragraph run.
+ *
+ * @param[in] attribute the relative line height attribute.
+ * @param[in,out] boundedParagraphRun The bounded paragraph run.
+ */
+void ProcessRelativeLineHeight(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun);
+
} // namespace Text
} // namespace Toolkit
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
#include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
#include <dali-toolkit/internal/text/markup-processor-underline.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
namespace Dali
{
{
namespace Text
{
-namespace
-{
-const std::string XHTML_FAMILY_ATTRIBUTE("font-family");
-const std::string XHTML_SIZE_ATTRIBUTE("font-size");
-const std::string XHTML_WEIGHT_ATTRIBUTE("font-weight");
-const std::string XHTML_WIDTH_ATTRIBUTE("font-width");
-const std::string XHTML_SLANT_ATTRIBUTE("font-slant");
-
-const std::string XHTML_COLOR_ATTRIBUTE("text-color");
-const std::string XHTML_BACKGROUND_COLOR_ATTRIBUTE("background-color");
-
-//the underlined character's attributes
-const std::string XHTML_UNDERLINE_COLOR_ATTRIBUTE("u-color");
-const std::string XHTML_UNDERLINE_HEIGHT_ATTRIBUTE("u-height");
-const std::string XHTML_UNDERLINE_TYPE_ATTRIBUTE("u-type");
-const std::string XHTML_UNDERLINE_DASH_GAP_ATTRIBUTE("u-dash-gap");
-const std::string XHTML_UNDERLINE_DASH_WIDTH_ATTRIBUTE("u-dash-width");
-
-//the strikethroughed character's attributes
-const std::string XHTML_STRIKETHROUGH_COLOR_ATTRIBUTE("s-color");
-const std::string XHTML_STRIKETHROUGH_HEIGHT_ATTRIBUTE("s-height");
-
-//the character-spacing character's attributes
-const std::string XHTML_CHARACTER_SPACING_VALUE_ATTRIBUTE("char-space-value");
-
-//NOTE: the MAX_NUM_OF_ATTRIBUTES in "markup-processor.cpp" should be updated when add a new attribute for span tag.
-
-} // namespace
-
void ProcessSpanTag(const Tag& tag,
ColorRun& colorRun,
FontDescriptionRun& fontRun,
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::TEXT_COLOR, attribute.nameBuffer, attribute.nameLength))
{
isColorDefined = true;
ProcessColor(attribute, colorRun);
}
- else if(TokenComparison(XHTML_BACKGROUND_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::BACKGROUND_COLOR, attribute.nameBuffer, attribute.nameLength))
{
isBackgroundColorDefined = true;
ProcessColor(attribute, backgroundColorRun);
}
- else if(TokenComparison(XHTML_FAMILY_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_FAMILY, attribute.nameBuffer, attribute.nameLength))
{
isFontDefined = true;
ProcessFontFamily(attribute, fontRun);
}
- else if(TokenComparison(XHTML_SIZE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_SIZE, attribute.nameBuffer, attribute.nameLength))
{
isFontDefined = true;
ProcessFontSize(attribute, fontRun);
}
- else if(TokenComparison(XHTML_WEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_WEIGHT, attribute.nameBuffer, attribute.nameLength))
{
isFontDefined = true;
ProcessFontWeight(attribute, fontRun);
}
- else if(TokenComparison(XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_WIDTH, attribute.nameBuffer, attribute.nameLength))
{
isFontDefined = true;
ProcessFontWidth(attribute, fontRun);
}
- else if(TokenComparison(XHTML_SLANT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_SLANT, attribute.nameBuffer, attribute.nameLength))
{
isFontDefined = true;
ProcessFontSlant(attribute, fontRun);
}
- else if(TokenComparison(XHTML_UNDERLINE_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_COLOR, attribute.nameBuffer, attribute.nameLength))
{
isUnderlinedCharacterDefined = true;
ProcessColorAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_UNDERLINE_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_HEIGHT, attribute.nameBuffer, attribute.nameLength))
{
isUnderlinedCharacterDefined = true;
ProcessHeightAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_UNDERLINE_TYPE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_TYPE, attribute.nameBuffer, attribute.nameLength))
{
isUnderlinedCharacterDefined = true;
ProcessTypeAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_UNDERLINE_DASH_GAP_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_DASH_GAP, attribute.nameBuffer, attribute.nameLength))
{
isUnderlinedCharacterDefined = true;
ProcessDashGapAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_UNDERLINE_DASH_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_DASH_WIDTH, attribute.nameBuffer, attribute.nameLength))
{
isUnderlinedCharacterDefined = true;
ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_STRIKETHROUGH_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::STRIKETHROUGH_COLOR, attribute.nameBuffer, attribute.nameLength))
{
isStrikethroughDefined = true;
ProcessColorAttribute(attribute, strikethroughRun);
}
- else if(TokenComparison(XHTML_STRIKETHROUGH_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::STRIKETHROUGH_HEIGHT, attribute.nameBuffer, attribute.nameLength))
{
isStrikethroughDefined = true;
ProcessHeightAttribute(attribute, strikethroughRun);
}
- else if(TokenComparison(XHTML_CHARACTER_SPACING_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::CHARACTER_SPACING_VALUE, attribute.nameBuffer, attribute.nameLength))
{
isCharacterSpacingDefined = true;
ProcessValueAttribute(attribute, characterSpacingCharacterRun);
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
#include <dali-toolkit/internal/text/strikethrough-character-run.h>
namespace Dali
{
namespace Text
{
-namespace
-{
-const std::string XHTML_COLOR_ATTRIBUTE("color");
-const std::string XHTML_HEIGHT_ATTRIBUTE("height");
-} // namespace
-
void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun)
{
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::STRIKETHROUGH_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
{
ProcessColorAttribute(attribute, strikethroughRun);
}
- else if(TokenComparison(XHTML_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::STRIKETHROUGH_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
{
ProcessHeightAttribute(attribute, strikethroughRun);
}
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
#include <dali-toolkit/internal/text/text-effects-style.h>
#include <dali-toolkit/internal/text/underlined-character-run.h>
{
namespace
{
-const std::string XHTML_COLOR_ATTRIBUTE("color");
-const std::string XHTML_HEIGHT_ATTRIBUTE("height");
-const std::string XHTML_TYPE_ATTRIBUTE("type");
-const std::string XHTML_DASH_GAP_ATTRIBUTE("dash-gap");
-const std::string XHTML_DASH_WIDTH_ATTRIBUTE("dash-width");
-
const unsigned int MAX_TYPE_ATTRIBUTE_SIZE = 7u; ///< The maximum length of any of the possible 'type' values.
} // namespace
{
const Attribute& attribute(*it);
- if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
{
ProcessColorAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
{
ProcessHeightAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_TYPE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::TYPE, attribute.nameBuffer, attribute.nameLength))
{
ProcessTypeAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_DASH_GAP_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::DASH_GAP, attribute.nameBuffer, attribute.nameLength))
{
ProcessDashGapAttribute(attribute, underlinedCharacterRun);
}
- else if(TokenComparison(XHTML_DASH_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::DASH_WIDTH, attribute.nameBuffer, attribute.nameLength))
{
ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
}
#include <dali-toolkit/internal/text/markup-processor-span.h>
#include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
#include <dali-toolkit/internal/text/markup-processor-underline.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
#include <dali-toolkit/internal/text/xhtml-entities.h>
namespace Dali
{
namespace
{
-// HTML-ISH tag and attribute constants.
-// Note they must be lower case in order to make the comparison to work
-// as the parser converts all the read tags to lower case.
-const std::string XHTML_COLOR_TAG("color");
-const std::string XHTML_FONT_TAG("font");
-const std::string XHTML_B_TAG("b");
-const std::string XHTML_I_TAG("i");
-const std::string XHTML_U_TAG("u");
-const std::string XHTML_SHADOW_TAG("shadow");
-const std::string XHTML_GLOW_TAG("glow");
-const std::string XHTML_OUTLINE_TAG("outline");
-const std::string XHTML_ITEM_TAG("item");
-const std::string XHTML_ANCHOR_TAG("a");
-const std::string XHTML_BACKGROUND_TAG("background");
-const std::string XHTML_SPAN_TAG("span");
-const std::string XHTML_STRIKETHROUGH_TAG("s");
-const std::string XHTML_PARAGRAPH_TAG("p");
-const std::string XHTML_CHARACTER_SPACING_TAG("char-spacing");
-
const char LESS_THAN = '<';
const char GREATER_THAN = '>';
const char EQUAL = '=';
markupStringEndBuffer,
tag))
{
- if(TokenComparison(XHTML_COLOR_TAG, tag.buffer, tag.length))
+ if(TokenComparison(MARKUP::TAG::COLOR, tag.buffer, tag.length))
{
ProcessTagForRun<ColorRun>(
markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) { ProcessColorTag(tag, run); });
} // <color></color>
- else if(TokenComparison(XHTML_I_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::ITALIC, tag.buffer, tag.length))
{
ProcessTagForRun<FontDescriptionRun>(
markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, iTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
fontRun.slantDefined = true;
});
} // <i></i>
- else if(TokenComparison(XHTML_U_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::UNDERLINE, tag.buffer, tag.length))
{
ProcessTagForRun<UnderlinedCharacterRun>(
markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { ProcessUnderlineTag(tag, run); });
} // <u></u>
- else if(TokenComparison(XHTML_B_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::BOLD, tag.buffer, tag.length))
{
ProcessTagForRun<FontDescriptionRun>(
markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, bTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
fontRun.weightDefined = true;
});
} // <b></b>
- else if(TokenComparison(XHTML_FONT_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::FONT, tag.buffer, tag.length))
{
ProcessTagForRun<FontDescriptionRun>(
markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, fontTagReference, [](const Tag& tag, FontDescriptionRun& fontRun) { ProcessFontTag(tag, fontRun); });
} // <font></font>
- else if(TokenComparison(XHTML_ANCHOR_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::ANCHOR, tag.buffer, tag.length))
{
/* Anchor */
ProcessAnchorTag(markupProcessData, tag, characterIndex);
ProcessUnderlineTag(tag, run);
});
} // <a href=https://www.tizen.org>tizen</a>
- else if(TokenComparison(XHTML_SHADOW_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::SHADOW, tag.buffer, tag.length))
{
// TODO: If !tag.isEndTag, then create a new shadow run.
// else Pop the top of the stack and set the number of characters of the run.
} // <shadow></shadow>
- else if(TokenComparison(XHTML_GLOW_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::GLOW, tag.buffer, tag.length))
{
// TODO: If !tag.isEndTag, then create a new glow run.
// else Pop the top of the stack and set the number of characters of the run.
} // <glow></glow>
- else if(TokenComparison(XHTML_OUTLINE_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::OUTLINE, tag.buffer, tag.length))
{
// TODO: If !tag.isEndTag, then create a new outline run.
// else Pop the top of the stack and set the number of characters of the run.
} // <outline></outline>
- else if(TokenComparison(XHTML_ITEM_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::EMBEDDED_ITEM, tag.buffer, tag.length))
{
ProcessItemTag(markupProcessData, tag, characterIndex);
}
- else if(TokenComparison(XHTML_BACKGROUND_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::BACKGROUND, tag.buffer, tag.length))
{
ProcessTagForRun<ColorRun>(
markupProcessData.backgroundColorRuns, styleStack, tag, characterIndex, backgroundRunIndex, backgroundTagReference, [](const Tag& tag, ColorRun& run) { ProcessBackground(tag, run); });
}
- else if(TokenComparison(XHTML_SPAN_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::SPAN, tag.buffer, tag.length))
{
ProcessSpanForRun(tag,
spanStack,
characterIndex,
spanTagReference);
}
- else if(TokenComparison(XHTML_STRIKETHROUGH_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::STRIKETHROUGH, tag.buffer, tag.length))
{
ProcessTagForRun<StrikethroughCharacterRun>(
markupProcessData.strikethroughCharacterRuns, styleStack, tag, characterIndex, strikethroughCharacterRunIndex, sTagReference, [](const Tag& tag, StrikethroughCharacterRun& run) { ProcessStrikethroughTag(tag, run); });
} // <s></s>
- else if(TokenComparison(XHTML_PARAGRAPH_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::PARAGRAPH, tag.buffer, tag.length))
{
ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex);
ProcessTagForRun<BoundedParagraphRun>(
markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
} // <p></p>
- else if(TokenComparison(XHTML_CHARACTER_SPACING_TAG, tag.buffer, tag.length))
+ else if(TokenComparison(MARKUP::TAG::CHARACTER_SPACING, tag.buffer, tag.length))
{
ProcessTagForRun<CharacterSpacingCharacterRun>(
markupProcessData.characterSpacingCharacterRuns, styleStack, tag, characterIndex, characterSpacingCharacterRunIndex, characterSpacingTagReference, [](const Tag& tag, CharacterSpacingCharacterRun& run) { ProcessCharacterSpacingTag(tag, run); });
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUPS_AND_ATTRIBUTES_H
+#define DALI_TOOLKIT_TEXT_MARKUPS_AND_ATTRIBUTES_H
+
+/*
+ * Copyright (c) 2022 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Use markup styling to style Text-Controller.
+ * The markup tag is opend by <> and closed by </>
+ *
+ * @details You can use markup elements to change the style of the text.
+ * Since the text controls do not process markup elements by default, you must first set the EnableMarkup property of the Text-Controller to true:
+ *
+ * @note The markup processor does not check for markup validity, and styles are rendered in priority order.
+ * Incorrect or incompatible elements can cause the text to be rendered incorrectly.
+ */
+namespace MARKUP
+{
+namespace TAG
+{
+// HTML-ISH tag and attribute constants.
+// Note they must be lower case in order to make the comparison to work
+// as the parser converts all the read tags to lower case.
+
+/**
+ * @brief Sets the color for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<color value='red'>Hello world</color>";
+ *
+ * @endcode
+ *
+ * @see COLOR_ATTRIBUTES
+ *
+ */
+static const std::string COLOR("color");
+
+/**
+ * @brief Sets the font values for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<font family='DejaVuSerif' size='18'>Hello world</font>";
+ *
+ * @endcode
+ *
+ * @see FONT_ATTRIBUTES
+ */
+static const std::string FONT("font");
+
+/**
+ * @brief Sets Bold decoration for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<b>Hello world</b>";
+ *
+ * @endcode
+ *
+ * @see
+ */
+static const std::string BOLD("b");
+
+/**
+ * @brief Sets Italic decoration for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<i>Hello world</i>";
+ *
+ * @endcode
+ *
+ */
+static const std::string ITALIC("i");
+
+/**
+ * @brief Sets the underlined values for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<u>Hello world</u>";
+ *
+ * @endcode
+ *
+ * @see UNDERLINE_ATTRIBUTES
+ */
+static const std::string UNDERLINE("u");
+
+/**
+ * @todo Sets the shadow for the characters inside the element.
+ *
+ */
+static const std::string SHADOW("shadow"); ///< This tag under construction.
+
+/**
+ * @todo Sets the glow for the characters inside the element.
+ *
+ */
+static const std::string GLOW("glow"); ///< This tag under construction.
+
+/**
+ * @todo Sets the outline for the characters inside the element.
+ *
+ */
+static const std::string OUTLINE("outline"); ///< This tag under construction.
+
+/**
+ * @brief Defines an embedded item within the text.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<item 'width'=26 'height'=26 'url'='path/image.png' 'color-blending'='multiply'/>";
+ *
+ * @endcode
+ *
+ * @see EMBEDDED_ITEM_ATTRIBUTES
+ */
+static const std::string EMBEDDED_ITEM("item");
+
+/**
+ * @brief Defines a hyperlink for the text inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<a href='https://www.tizen.org'>TIZEN</a>";
+ *
+ * @endcode
+ *
+ * @see ANCHOR_ATTRIBUTES
+ */
+static const std::string ANCHOR("a");
+
+/**
+ * @brief Sets the background color for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<background color='yellow'>Hello world</background>";
+ *
+ * @endcode
+ *
+ * @see BACKGROUND_ATTRIBUTES
+ */
+static const std::string BACKGROUND("background");
+
+/**
+ * @brief Use span tag to set many styles on character's level for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<span font-size='20' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='green' char-space-value='10.0f'>Hello world</span>";
+ *
+ * @endcode
+ *
+ * @see SPAN_ATTRIBUTES
+ */
+static const std::string SPAN("span");
+
+/**
+ * @brief Sets the strikethrough values for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<s>Hello world</s>";
+ *
+ * @endcode
+ *
+ * @see STRIKETHROUGH_ATTRIBUTES
+ */
+static const std::string STRIKETHROUGH("s");
+
+/**
+ * @brief Use paragraph tag to set many styles on paragraph's level for the lines inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "test before paragraph tag <p>test paragraph tag </p>test after paragraph tag ";
+ *
+ * @endcode
+ *
+ * @see PARAGRAPH_ATTRIBUTES
+ */
+static const std::string PARAGRAPH("p");
+
+/**
+ * @brief Sets the character spacing values for the characters inside the element.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<char-spacing value='3.0f'>Hello world</char-spacing>";
+ *
+ * @endcode
+ *
+ * @see CHARACTER_SPACING_ATTRIBUTES
+ */
+static const std::string CHARACTER_SPACING("char-spacing");
+} // namespace TAG
+
+namespace COLOR_ATTRIBUTES
+{
+/**
+ * @brief Use the value attribute to define the color.
+ * The supported attribute values are red, green, blue, yellow, magenta, cyan, white, black, and transparent.
+ * Web colors and colors represented in 32-bit hexadecimal 0xAARRGGBB format are also supported.
+ *
+ * The following examples show text in red color:
+ * @code
+ *
+ * textController.Text = "<color value='red'>Hello world</color>"; /// Color coded with a text constant
+ *
+ * @endcode
+ *
+ * @code
+ *
+ * textController.Text = "<color value='0xFFFF0000'>Hello world</color>"); /// Color packed inside an ARGB hexadecimal value
+ *
+ * @endcode
+ */
+static const std::string VALUE("value");
+} // namespace COLOR_ATTRIBUTES
+
+namespace FONT_ATTRIBUTES
+{
+/**
+ * @brief Use the family attribute to define the font name.
+ *
+ * Example:
+ * @code
+ *
+ * textController.Text = "<font family='SamsungSans' >Hello world</font>";
+ *
+ * @endcode
+ *
+ */
+static const std::string FAMILY("family");
+
+/**
+ * @brief Use the size attribute to define the font size in points.
+ *
+ * Example:
+ * @code
+ *
+ * textController.Text = "<font size='50' >Hello world</font>";
+ *
+ * @endcode
+ *
+ */
+static const std::string SIZE("size");
+
+/**
+ * @brief Use the weight attribute to define the font weight.
+ *
+ * Example:
+ * @code
+ *
+ * textController.Text = "<font weight='bold' >Hello world</font>";
+ *
+ * @endcode
+ *
+ */
+static const std::string WEIGHT("weight");
+
+/**
+ * @brief Use the width attribute to define the font width.
+ *
+ * Example:
+ * @code
+ *
+ * textController.Text = "<font width='condensed' >Hello world</font>";
+ *
+ * @endcode
+ *
+ */
+static const std::string WIDTH("width");
+
+/**
+ * @brief Use the slant attribute to define the font slant.
+ *
+ * Example:
+ * @code
+ *
+ * textController.Text = "<font slant='italic' >Hello world</font>";
+ *
+ * @endcode
+ *
+ */
+static const std::string SLANT("slant");
+} // namespace FONT_ATTRIBUTES
+
+namespace UNDERLINE_ATTRIBUTES
+{
+/**
+ * @brief Use the color attribute to define the color of underline.
+ * The supported attribute values are red, green, blue, yellow, magenta, cyan, white, black, and transparent.
+ * Web colors and colors represented in 32-bit hexadecimal 0xAARRGGBB format are also supported.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<u color='green'>Hello world</u>";
+ *
+ * @endcode
+ */
+static const std::string COLOR("color");
+
+/**
+ * @brief Use the height attribute to define the height of underline.
+ * It is float value.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<u height='2.0f'>Hello world</u>";
+ *
+ * @endcode
+ */
+static const std::string HEIGHT("height");
+
+/**
+ * @brief Use the type attribute to define the type of underline.
+ * The supported attribute values are solid, dashed and double
+ * The default value is solid
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<u type='double'>Hello world</u>";
+ *
+ * @endcode
+ */
+static const std::string TYPE("type");
+
+/**
+ * @brief Use the dash-gap attribute to define the dash-gap of underline.
+ * The gap in pixels between the dashes of the dashed underline. Only valid when "DASHED" underline type is used.
+ *
+ * It is float value.
+ * @note If not provided then the default gap is used (1 pixel).
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<u type='dashed' dash-gap='2.0f'>Hello world</u>";
+ *
+ * @endcode
+ */
+static const std::string DASH_GAP("dash-gap");
+
+/**
+ * @brief Use the dash-width attribute to define the dash-width of underline.
+ * The width in pixels of the dashes of the dashed underline. Only valid when "DASHED" underline type is used.
+ * It is float value.
+ * @note If not provided then the default width is used (2 pixel).
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<u type='dashed' dash-width='3.0f'>Hello world</u>";
+ *
+ * @endcode
+ */
+static const std::string DASH_WIDTH("dash-width");
+
+} // namespace UNDERLINE_ATTRIBUTES
+
+namespace SPAN_ATTRIBUTES
+{
+//NOTE: the MAX_NUM_OF_ATTRIBUTES in "markup-processor.cpp" should be updated when add a new attribute for span tag.
+
+/**
+ * @brief The font family attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span font-family='SamsungSans' >Hello world</span>";
+ * @endcode
+ * @see FONT_ATTRIBUTES::FAMILY
+ */
+static const std::string FONT_FAMILY("font-family");
+
+/**
+ * @brief The font size attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span font-size='50' >Hello world</span>";
+ * @endcode
+ * @see FONT_ATTRIBUTES::SIZE
+ */
+static const std::string FONT_SIZE("font-size");
+
+/**
+ * @brief The font weight attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span font-weight='bold' >Hello world</span>";
+ * @endcode
+ * @see FONT_ATTRIBUTES::WEIGHT
+ */
+static const std::string FONT_WEIGHT("font-weight");
+
+/**
+ * @brief The font width attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span font-width='condensed' >Hello world</span>";
+ * @endcode
+ * @see FONT_ATTRIBUTES::WIDTH
+ */
+static const std::string FONT_WIDTH("font-width");
+
+/**
+ * @brief The font slant attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span font-slant='italic' >Hello world</span>";
+ * @endcode
+ * @see FONT_ATTRIBUTES::SLANT
+ */
+static const std::string FONT_SLANT("font-slant");
+
+/**
+ * @brief The color value attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span text-color='blue' >Hello world</span>";
+ * @endcode
+ * @see COLOR_ATTRIBUTES::VALUE
+ */
+static const std::string TEXT_COLOR("text-color");
+
+/**
+ * @brief The background color attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span background-color='yellow' >Hello world</span>";
+ * @endcode
+ * @see BACKGROUND_ATTRIBUTES::COLOR
+ */
+static const std::string BACKGROUND_COLOR("background-color");
+
+/**
+ * @brief The undeline color attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span u-color='green' >Hello world</span>";
+ * @endcode
+ * @see UNDERLINE_ATTRIBUTES::COLOR
+ */
+static const std::string UNDERLINE_COLOR("u-color");
+
+/**
+ * @brief The undeline height attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span u-height='3.0f' >Hello world</span>";
+ * @endcode
+ * @see UNDERLINE_ATTRIBUTES::HEIGHT
+ */
+static const std::string UNDERLINE_HEIGHT("u-height");
+
+/**
+ * @brief The undeline type attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span u-type='solid' >Hello world</span>";
+ * @endcode
+ * @see UNDERLINE_ATTRIBUTES::TYPE
+ */
+static const std::string UNDERLINE_TYPE("u-type");
+
+/**
+ * @brief The undeline dash-gap attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span u-type='dashed' u-dash-gap='2.0f' >Hello world</span>";
+ * @endcode
+ * @see UNDERLINE_ATTRIBUTES::DASH_GAP
+ */
+static const std::string UNDERLINE_DASH_GAP("u-dash-gap");
+
+/**
+ * @brief The undeline dash-width attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span u-type='dashed' u-dash-width='4.0f' >Hello world</span>";
+ * @endcode
+ * @see UNDERLINE_ATTRIBUTES::DASH_WIDTH
+ */
+static const std::string UNDERLINE_DASH_WIDTH("u-dash-width");
+
+/**
+ * @brief The strikethrough color attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span s-color='green' >Hello world</span>";
+ * @endcode
+ * @see STRIKETHROUGH_ATTRIBUTES::COLOR
+ */
+static const std::string STRIKETHROUGH_COLOR("s-color");
+
+/**
+ * @brief The strikethrough height attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span s-height='3.0f' >Hello world</span>";
+ * @endcode
+ * @see STRIKETHROUGH_ATTRIBUTES::HEIGHT
+ */
+static const std::string STRIKETHROUGH_HEIGHT("s-height");
+
+/**
+ * @brief The character-spacing value attribute.
+ *
+ * Example:
+ * @code
+ * textController.Text = "<span char-space-value='5.0f' >Hello world</span>";
+ * @endcode
+ * @see CHARACTER_SPACING_ATTRIBUTES::VALUE
+ */
+static const std::string CHARACTER_SPACING_VALUE("char-space-value");
+} // namespace SPAN_ATTRIBUTES
+
+namespace STRIKETHROUGH_ATTRIBUTES
+{
+/**
+ * @brief Use the color attribute to define the color of strikethrough.
+ * The supported attribute values are red, green, blue, yellow, magenta, cyan, white, black, and transparent.
+ * Web colors and colors represented in 32-bit hexadecimal 0xAARRGGBB format are also supported.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<s color='green'>Hello world</s>";
+ *
+ * @endcode
+ */
+static const std::string COLOR("color");
+
+/**
+ * @brief Use the height attribute to define the height of strikethrough.
+ * It is float value.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<s height='2.0f'>Hello world</s>";
+ *
+ * @endcode
+ */
+static const std::string HEIGHT("height");
+} // namespace STRIKETHROUGH_ATTRIBUTES
+
+namespace PARAGRAPH_ATTRIBUTES
+{
+/**
+ * @brief Use the align attribute to define the horizontal alignment of paragraph.
+ * The supported attribute values are begin, center and end .
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = ""text outside<p align='end'>Paragraph end</p>text outside<p align='center'>Paragraph center</p>text outside<p align='begin' >Paragraph begin</p>";
+ *
+ * @endcode
+ */
+static const std::string ALIGN("align");
+
+/**
+ * @brief Use the rrel-line-height attribute to define the relative height of the line (a factor that will be multiplied by text height).
+ * It is float value.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<p>line 1</p><p rel-line-height=0.5>line\n2</p>line 3<p rel-line-height=3>line\n4</p>line 5";
+ *
+ * @endcode
+ * @note If the value is less than 1, the lines could to be overlapped.
+ */
+static const std::string RELATIVE_LINE_HEIGHT("rel-line-height");
+
+} // namespace PARAGRAPH_ATTRIBUTES
+
+namespace CHARACTER_SPACING_ATTRIBUTES
+{
+/**
+ * @brief Use the value attribute to define the spaces between characters in Pixels.
+ * A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
+ *
+ * Examples:
+ * @code
+ *
+ * textController.Text = "<char-spacing value='5.0f'>Hello world</char-spacing>"; /// Expanded
+ *
+ * @endcode
+ *
+ * @code
+ *
+ * textController.Text = "<char-spacing value='-5.0f'>Hello world</char-spacing>"); /// Condensed
+ *
+ * @endcode
+ */
+static const std::string VALUE("value");
+} // namespace CHARACTER_SPACING_ATTRIBUTES
+namespace BACKGROUND_ATTRIBUTES
+{
+/**
+ * @brief Use the value attribute to define the color of background.
+ * The supported attribute values are red, green, blue, yellow, magenta, cyan, white, black, and transparent.
+ * Web colors and colors represented in 32-bit hexadecimal 0xAARRGGBB format are also supported.
+ *
+ * The following example explains how to apply it:
+ * @code
+ *
+ * textController.Text = "<background color='green'>Hello world</background>";
+ *
+ * @endcode
+ */
+static const std::string COLOR("color");
+
+} // namespace BACKGROUND_ATTRIBUTES
+
+namespace EMBEDDED_ITEM_ATTRIBUTES
+{
+/**
+ * @brief Use the url attribute to define url path of the image.
+ *
+ * @note The url of the image is optional. If there is no image
+ * the layout engine will use the width and height to
+ * create a space inside the text. This gap can be filled later.
+ */
+static const std::string URL("url");
+
+/**
+ * @brief Use the width attribute to define the width of the item.
+ */
+static const std::string WIDTH("width");
+
+/**
+ * @brief Use the height attribute to define the height of the item.
+ */
+static const std::string HEIGHT("height");
+
+/**
+ * @brief Use the color-blending attribute to define whether the color of the image is multiplied by the color of the text.
+ *
+ * @note A color blending mode can be set. The default is NONE, the image will use its own color. If MULTIPLY is set, the color
+ * of the image will be multiplied by the color of the text.
+ */
+static const std::string COLOR_BLENDING("color-blending");
+} // namespace EMBEDDED_ITEM_ATTRIBUTES
+
+namespace ANCHOR_ATTRIBUTES
+{
+/**
+ * @brief Use the href attribute to define the url of hyperlink.
+ */
+static const std::string HREF("href");
+
+} // namespace ANCHOR_ATTRIBUTES
+
+} // namespace MARKUP
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUPS_AND_ATTRIBUTES_H
// Increases the vertical offset with the line's ascender.
glyphData.verticalOffset += static_cast<int>(line.ascender);
- // Include line spacing after first line
- if(lineIndex > 0u)
- {
- glyphData.verticalOffset += static_cast<int>(line.lineSpacing);
- }
-
// Retrieves the glyph's outline width
float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
DrawStrikethrough(bufferWidth, bufferHeight, glyphData, baseline, strikethroughStartingYPosition, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, modelStrikethroughProperties, currentStrikethroughProperties, line);
}
- // Increases the vertical offset with the line's descender.
- glyphData.verticalOffset += static_cast<int>(-line.descender);
+ // Increases the vertical offset with the line's descender & line spacing.
+ glyphData.verticalOffset += static_cast<int>(-line.descender+line.lineSpacing);
}
return glyphData.bitmapBuffer;
bool textChanged = false;
bool relayoutNeeded = false;
+ bool isEditable = controller.IsEditable() && controller.IsUserInteractionEnabled();
if((NULL != controller.mImpl->mEventData) &&
(keyEvent.GetState() == KeyEvent::DOWN))
(Dali::DALI_KEY_CURSOR_DOWN == keyCode))
{
// If don't have any text, do nothing.
- if(!controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters)
+ if(!controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters || !isEditable)
{
return false;
}
// Do nothing
return false;
}
- else if(keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier())
+ else if(keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier() && isEditable)
{
bool consumed = false;
if(keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME || logicalKey == KEY_C_NAME || logicalKey == KEY_INSERT_NAME)
else
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", &controller, keyString.c_str());
- if(!controller.IsEditable()) return false;
+ if(!isEditable) return false;
std::string refinedKey = keyString;
if(controller.mImpl->mInputFilter != NULL && !refinedKey.empty())
impl.GetCursorPosition(primaryCursorPosition, cursorInfo);
// Get the line below.
- const LineRun& line = *(visualModel->mLines.Begin() + lineIndex + 1u);
+ const LineRun& nextline = *(visualModel->mLines.Begin() + lineIndex + 1u);
+ const LineRun& currline = *(visualModel->mLines.Begin() + lineIndex);
// Get last line index
const LineIndex lastLineIndex = (visualModel->mLines.Size() > 0 ? visualModel->mLines.Size() - 1u : 0);
const bool isLastLine = (lineIndex + 1u == lastLineIndex);
// Get the next hit 'y' point.
- const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * GetLineHeight(line, isLastLine);
+ const float hitPointY = cursorInfo.lineOffset + GetLineHeight(currline, false) + 0.5f * GetLineHeight(nextline, isLastLine);
// Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
bool matchedCharacter = false;
}
}
+void UpdateCursorPositionForAlignment(Controller::Impl& impl, bool needFullAlignment)
+{
+ EventData* eventData = impl.mEventData;
+
+ // Set the flag to redo the alignment operation
+ impl.mOperationsPending = static_cast<Controller::OperationsMask>(impl.mOperationsPending | Controller::OperationsMask::ALIGN);
+
+ if(eventData)
+ {
+ // Note: mUpdateAlignment is currently only needed for horizontal alignment
+ eventData->mUpdateAlignment = needFullAlignment;
+
+ // Update the cursor if it's in editing mode
+ if(EventData::IsEditingState(eventData->mState))
+ {
+ impl.ChangeState(EventData::EDITING);
+ eventData->mUpdateCursorPosition = true;
+ }
+ }
+}
+
} // unnamed Namespace
EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
if(mEventData->mDecorator)
{
- mEventData->mDecorator->SetEditable(editable);
+ bool decoratorEditable = editable && mIsUserInteractionEnabled;
+ mEventData->mDecorator->SetEditable(decoratorEditable);
}
}
}
{
mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
}
+ else if(mModel->mLogicalModel->mText.Count() == 0u)
+ {
+ Relayouter::CalculateVerticalOffset(*this, mModel->mVisualModel->mControlSize);
+ }
}
}
{
// Set the alignment.
mModel->mHorizontalAlignment = alignment;
-
- // Set the flag to redo the alignment operation.
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
-
- if(mEventData)
- {
- mEventData->mUpdateAlignment = true;
-
- // Update the cursor if it's in editing mode
- if(EventData::IsEditingState(mEventData->mState))
- {
- ChangeState(EventData::EDITING);
- mEventData->mUpdateCursorPosition = true;
- }
- }
-
+ UpdateCursorPositionForAlignment(*this, true);
RequestRelayout();
}
}
{
// Set the alignment.
mModel->mVerticalAlignment = alignment;
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
+ UpdateCursorPositionForAlignment(*this, false);
RequestRelayout();
}
}
}
}
+void Controller::Impl::SetUserInteractionEnabled(bool enabled)
+{
+ mIsUserInteractionEnabled = enabled;
+
+ if(mEventData && mEventData->mDecorator)
+ {
+ bool editable = mEventData->mEditingEnabled && enabled;
+ mEventData->mDecorator->SetEditable(editable);
+ }
+}
+
void Controller::Impl::ClearFontData()
{
if(mFontDefaults)
const float DEFAULT_TEXTFIT_MAX = 100.f;
const float DEFAULT_TEXTFIT_STEP = 1.f;
const float DEFAULT_FONT_SIZE_SCALE = 1.f;
+const float DEFAULT_DISABLED_COLOR_OPACITY = 0.3f;
//Forward declarations
struct CursorInfo;
mTextFitMaxSize(DEFAULT_TEXTFIT_MAX),
mTextFitStepSize(DEFAULT_TEXTFIT_STEP),
mFontSizeScale(DEFAULT_FONT_SIZE_SCALE),
+ mDisabledColorOpacity(DEFAULT_DISABLED_COLOR_OPACITY),
mFontSizeScaleEnabled(true),
mTextFitEnabled(false),
mTextFitChanged(false),
- mIsLayoutDirectionChanged(false)
+ mIsLayoutDirectionChanged(false),
+ mIsUserInteractionEnabled(true)
{
mModel = Model::New();
void SetDefaultColor(const Vector4& color);
/**
+ * @copydoc Controller::SetUserInteractionEnabled()
+ */
+ void SetUserInteractionEnabled(bool enabled);
+
+ /**
* @brief Helper to clear font-specific data (only).
*/
void ClearFontData();
float mTextFitMaxSize; ///< Maximum Font Size for text fit. Default 100
float mTextFitStepSize; ///< Step Size for font intervalse. Default 1
float mFontSizeScale; ///< Scale value for Font Size. Default 1.0
+ float mDisabledColorOpacity; ///< Color opacity when disabled.
bool mFontSizeScaleEnabled : 1; ///< Whether the font size scale is enabled.
bool mTextFitEnabled : 1; ///< Whether the text's fit is enabled.
bool mTextFitChanged : 1; ///< Whether the text fit property has changed.
bool mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed.
+ bool mIsUserInteractionEnabled : 1; ///< Whether the user interaction is enabled.
private:
friend ControllerImplEventHandler;
SHAPE_TEXT |
GET_GLYPH_METRICS);
+ const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT | ALIGN | REORDER);
+
// Set the update info to relayout the whole text.
TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
if((0 == textUpdateInfo.mNumberOfCharactersToAdd) &&
textUpdateInfo.mParagraphCharacterIndex = 0u;
textUpdateInfo.mRequestedNumberOfCharacters = model->mLogicalModel->mText.Count();
- // This is to keep Index to the first character to be updated.
- // Then restore it after calling Clear method.
- auto updateInfoCharIndexBackup = textUpdateInfo.mCharacterIndex;
-
// Get a reference to the pending operations member
OperationsMask& operationsPending = impl.mOperationsPending;
- // Layout the text for the new width.
- // Apply the pending operations, requested operations and the only once operations.
- // Then remove onlyOnceOperations
- operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask | onlyOnceOperations);
-
- // Make sure the model is up-to-date before layouting
- impl.UpdateModel(static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE));
-
// Store the actual control's size to restore later.
const Size actualControlSize = visualModel->mControlSize;
- DoRelayout(impl,
- requestedControllerSize,
- static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE),
- calculatedLayoutSize);
+ // Whether the text control is editable
+ const bool isEditable = NULL != impl.mEventData;
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.Clear();
+ if(!isEditable)
+ {
+ impl.UpdateModel(onlyOnceOperations);
- //TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel,
- //TODO: then calculate GlyphPositions. Lines, Size, Layout for Natural-Size
- //TODO: and utilize the values in OperationsPending and TextUpdateInfo without changing the original one.
- //TODO: Also it will improve performance because there is no need todo FullRelyout on the next need for layouting.
+ DoRelayout(impl,
+ requestedControllerSize,
+ static_cast<OperationsMask>(onlyOnceOperations | requestedOperationsMask),
+ calculatedLayoutSize);
- // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
- // By this no need to take backup and restore it.
- textUpdateInfo.mFullRelayoutNeeded = true;
+ textUpdateInfo.Clear();
+ textUpdateInfo.mClearAll = true;
- // Restore mCharacterIndex. Because "Clear" set it to the maximum integer.
- // The "CalculateTextUpdateIndices" does not work proprely because the mCharacterIndex will be greater than mPreviousNumberOfCharacters.
- // Which apply an assumption to update only the last paragraph. That could cause many of out of index crashes.
- textUpdateInfo.mCharacterIndex = updateInfoCharIndexBackup;
+ // Do not do again the only once operations.
+ operationsPending = static_cast<OperationsMask>(operationsPending & ~onlyOnceOperations);
+ }
+ else
+ {
+ // This is to keep Index to the first character to be updated.
+ // Then restore it after calling Clear method.
+ auto updateInfoCharIndexBackup = textUpdateInfo.mCharacterIndex;
- // Do not do again the only once operations.
- operationsPending = static_cast<OperationsMask>(operationsPending & ~onlyOnceOperations);
+ // Layout the text for the new width.
+ // Apply the pending operations, requested operations and the only once operations.
+ // Then remove onlyOnceOperations
+ operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask | onlyOnceOperations);
- // Do the size related operations again.
+ // Make sure the model is up-to-date before layouting
+ impl.UpdateModel(static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE));
+
+ DoRelayout(impl,
+ requestedControllerSize,
+ static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE),
+ calculatedLayoutSize);
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ textUpdateInfo.Clear();
+
+ //TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel,
+ //TODO: then calculate GlyphPositions. Lines, Size, Layout for Natural-Size
+ //TODO: and utilize the values in OperationsPending and TextUpdateInfo without changing the original one.
+ //TODO: Also it will improve performance because there is no need todo FullRelyout on the next need for layouting.
+
+ // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+ // By this no need to take backup and restore it.
+ textUpdateInfo.mFullRelayoutNeeded = true;
- const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
- ALIGN |
- REORDER);
+ // Restore mCharacterIndex. Because "Clear" set it to the maximum integer.
+ // The "CalculateTextUpdateIndices" does not work proprely because the mCharacterIndex will be greater than mPreviousNumberOfCharacters.
+ // Which apply an assumption to update only the last paragraph. That could cause many of out of index crashes.
+ textUpdateInfo.mCharacterIndex = updateInfoCharIndexBackup;
+ }
+ // Do the size related operations again.
operationsPending = static_cast<OperationsMask>(operationsPending | sizeOperations);
// Restore the actual control's size.
if(!isEditable || !controller.IsMultiLineEnabled())
{
// After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
- CalculateVerticalOffset(controller, size);
+ CalculateVerticalOffset(impl, size);
+ }
+ else // TextEditor
+ {
+ // If layoutSize is bigger than size, vertical align has no meaning.
+ if(layoutSize.y < size.y)
+ {
+ CalculateVerticalOffset(impl, size);
+ if(impl.mEventData)
+ {
+ impl.mEventData->mScrollAfterDelete = false;
+ }
+ }
}
if(isEditable)
}
}
-void Controller::Relayouter::CalculateVerticalOffset(Controller& controller, const Size& controlSize)
+void Controller::Relayouter::CalculateVerticalOffset(Controller::Impl& impl, const Size& controlSize)
{
- Controller::Impl& impl = *controller.mImpl;
ModelPtr& model = impl.mModel;
VisualModelPtr& visualModel = model->mVisualModel;
Size layoutSize = model->mVisualModel->GetLayoutSize();
/**
* @brief Called by the Controller to calculate the veritcal offset give the control size.
*
- * @param[in] controller A reference to the controller class
+ * @param[in] impl A reference to the controller impl class
* @param[in] controlSize The control size
*/
- static void CalculateVerticalOffset(Controller& controller, const Size& controlSize);
+ static void CalculateVerticalOffset(Controller::Impl& impl, const Size& controlSize);
/**
* @brief Calculates the layout size of control according to @p requestedControllerSize and @p requestedOperationsMask
return mImpl->mTextColor;
}
+void Controller::SetDisabledColorOpacity(float opacity)
+{
+ mImpl->mDisabledColorOpacity = opacity;
+}
+
+float Controller::GetDisabledColorOpacity() const
+{
+ return mImpl->mDisabledColorOpacity;
+}
+
+void Controller::SetUserInteractionEnabled(bool enabled)
+{
+ mImpl->SetUserInteractionEnabled(enabled);
+}
+
+bool Controller::IsUserInteractionEnabled() const
+{
+ return mImpl->mIsUserInteractionEnabled;
+}
+
void Controller::SetPlaceholderTextColor(const Vector4& textColor)
{
PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
bool IsTextFitChanged() const;
/**
+ * @brief Sets disabled color opacity.
+ *
+ * @param[in] opacity The color opacity value in disabled state.
+ */
+ void SetDisabledColorOpacity(float opacity);
+
+ /**
+ * @brief Retrieves the disabled color opacity.
+ *
+ * @return The disabled color opacity value for disabled state.
+ */
+ float GetDisabledColorOpacity() const;
+
+ /**
* @brief Enable or disable the placeholder text elide.
* @param enabled Whether to enable the placeholder text elide.
*/
const Vector4& GetDefaultColor() const;
/**
+ * @brief Sets the user interaction enabled.
+ *
+ * @param enabled whether to enable the user interaction.
+ */
+ void SetUserInteractionEnabled(bool enabled);
+
+ /**
+ * @brief Whether the user interaction is enabled.
+ *
+ * @return true if the user interaction is enabled, false otherwise.
+ */
+ bool IsUserInteractionEnabled() const;
+
+ /**
* @brief Set the text color
*
* @param textColor The text color
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
const TextureCacheManager::TextureId& maskTextureId,
- const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad)
+ const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
+ bool isAnimatedImage)
{
// Default to an invalid ID, in case we do not find a match.
TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
(useAtlas == textureInfo.useAtlas) &&
(maskTextureId == textureInfo.maskTextureId) &&
(size == textureInfo.desiredSize) &&
+ (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
((size.GetWidth() == 0 && size.GetHeight() == 0) ||
(fittingMode == textureInfo.fittingMode &&
samplingMode == textureInfo.samplingMode)))
if(textureInfoIndex != INVALID_CACHE_INDEX)
{
TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex]);
-
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%d) url:%s\n cacheIdx:%d loadState:%s reference count = %d\n", textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex, GET_LOAD_STATE_STRING(textureInfo.loadState), textureInfo.referenceCount);
// Decrement the reference count and check if this is the last user of this Texture.
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlas True if atlased
* @param[in] maskTextureId Optional texture ID to use to mask this image
- * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+ * @param[in] preMultiplyOnLoad If the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+ * @param[in] isAnimatedImage True if the texture is from animated image.
* @return A TextureCacheId of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
*/
TextureCacheManager::TextureCacheIndex FindCachedTexture(
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
const TextureCacheManager::TextureId& maskTextureId,
- const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad);
+ const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
+ bool isAnimatedImage);
/**
* @brief Append a Texture to the TextureCacheManager.
}
}
-TextureSet TextureManager::LoadAnimatedImageTexture(
- Dali::AnimatedImageLoading animatedImageLoading,
- const std::uint32_t& frameIndex,
- const Dali::SamplingMode::Type& samplingMode,
- const bool& synchronousLoading,
- TextureManager::TextureId& textureId,
- const Dali::WrapMode::Type& wrapModeU,
- const Dali::WrapMode::Type& wrapModeV,
- TextureUploadObserver* textureObserver)
+TextureSet TextureManager::LoadAnimatedImageTexture(Dali::AnimatedImageLoading animatedImageLoading,
+ const uint32_t& frameIndex,
+ TextureManager::TextureId& textureId,
+ const Dali::SamplingMode::Type& samplingMode,
+ const Dali::WrapMode::Type& wrapModeU,
+ const Dali::WrapMode::Type& wrapModeV,
+ const bool& synchronousLoading,
+ const bool& useCache,
+ TextureUploadObserver* textureObserver)
{
TextureSet textureSet;
else
{
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- textureId = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex, false);
+ textureId = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex, false, useCache);
TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
if(loadState == TextureManager::LoadState::UPLOADED)
{
}
else
{
- RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
+ RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false, false);
}
return pixelBuffer;
TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
const bool& synchronousLoading)
{
- return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
+ return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading, true);
}
TextureManager::TextureId TextureManager::RequestLoad(
TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
const bool& synchronousLoading)
{
- return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
+ return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading, true);
}
TextureManager::TextureId TextureManager::RequestMaskLoad(
{
// Use the normal load procedure to get the alpha mask.
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, UseAtlas::NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
+ return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, UseAtlas::NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading, true);
}
TextureManager::TextureId TextureManager::RequestLoadInternal(
TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
Dali::AnimatedImageLoading animatedImageLoading,
const std::uint32_t& frameIndex,
- const bool& synchronousLoading)
+ const bool& synchronousLoading,
+ const bool& useCache)
{
- // First check if the requested Texture is cached.
- bool isAnimatedImage = (animatedImageLoading) ? true : false;
-
TextureHash textureHash = INITIAL_HASH_NUMBER;
TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
- if(storageType != StorageType::RETURN_PIXEL_BUFFER && !isAnimatedImage)
+ if(storageType != StorageType::RETURN_PIXEL_BUFFER && useCache)
{
textureHash = mTextureCacheManager.GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId);
// Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
- cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad);
+ cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
}
TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
{
// If the image is already finished to load, use cached texture.
// We don't need to consider Observer because this is synchronous loading.
- if(textureInfo.loadState == TextureManager::LoadState::UPLOADED ||
- textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED)
- {
- return textureId;
- }
- else
+ if(!(textureInfo.loadState == TextureManager::LoadState::UPLOADED ||
+ textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED))
{
Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);
{
pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask);
}
+ else
+ {
+ DALI_LOG_ERROR("Mask image cached invalid pixel buffer!\n");
+ }
}
else
{
}
}
}
-
- // Return the TextureId for which this Texture can now be referenced by externally.
return textureId;
}
{
// The Texture has already loaded. The other observers have already been notified.
// We need to send a "late" loaded notification for this observer.
- observer->LoadComplete(true, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureInfo.textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied));
+ EmitLoadComplete(observer, textureInfo, true);
}
break;
}
if(cacheIndex != INVALID_CACHE_INDEX)
{
TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
- if(textureInfo.loadState == LoadState::UPLOADED)
+ if((textureInfo.loadState == LoadState::UPLOADED) || (textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER))
{
- element.mObserver->LoadComplete(true, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureInfo.textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied));
- }
- else if(textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER)
- {
- element.mObserver->LoadComplete(true, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, textureInfo.pixelBuffer, textureInfo.url.GetUrl(), textureInfo.preMultiplied));
+ EmitLoadComplete(element.mObserver, textureInfo, true);
}
else
{
// Send New Task to Thread
ApplyMask(textureInfo, textureInfo.maskTextureId);
}
+ else // maskLoadState == LoadState::LOAD_FAILED
+ {
+ // Url texture load success, But alpha mask texture load failed. Run as normal image upload.
+ DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n");
+ UploadTexture(pixelBuffer, textureInfo);
+ NotifyObservers(textureInfo, true);
+ }
}
}
else
else
{
textureInfo.loadState = LoadState::LOAD_FAILED;
- CheckForWaitingTexture(textureInfo);
- NotifyObservers(textureInfo, false);
+ if(textureInfo.storageType != StorageType::KEEP_PIXEL_BUFFER)
+ {
+ NotifyObservers(textureInfo, false);
+ }
+ else // if(textureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) // image mask case
+ {
+ // Check if there was another texture waiting for this load to complete
+ // (e.g. if this was an image mask, and its load is on a different thread)
+ CheckForWaitingTexture(textureInfo);
+ }
}
}
// maskTextureId:
const TextureCacheIndex size = static_cast<TextureCacheIndex>(mTextureCacheManager.size());
+ const bool maskLoadSuccess = maskTextureInfo.loadState == LoadState::LOAD_FINISHED ? true : false;
+
for(TextureCacheIndex cacheIndex = 0; cacheIndex < size; ++cacheIndex)
{
if(mTextureCacheManager[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
{
TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
- if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED)
+ if(maskLoadSuccess)
{
// Send New Task to Thread
ApplyMask(textureInfo, maskTextureInfo.textureId);
}
else
{
- textureInfo.pixelBuffer.Reset();
- textureInfo.loadState = LoadState::LOAD_FAILED;
- NotifyObservers(textureInfo, false);
+ // Url texture load success, But alpha mask texture load failed. Run as normal image upload.
+ DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n");
+ UploadTexture(textureInfo.pixelBuffer, textureInfo);
+ NotifyObservers(textureInfo, true);
}
}
}
// and erase it from the list
TextureInfo* info = &textureInfo;
+ if(info->animatedImageLoading)
+ {
+ // If loading failed, we don't need to get frameCount and frameInterval.
+ if(success)
+ {
+ info->frameCount = info->animatedImageLoading.GetImageCount();
+ info->frameInterval = info->animatedImageLoading.GetFrameInterval(info->frameIndex);
+ }
+ info->animatedImageLoading.Reset();
+ }
+
mQueueLoadFlag = true;
while(info->observerList.Count())
info->observerList.Erase(info->observerList.Begin());
- if(info->storageType == StorageType::RETURN_PIXEL_BUFFER)
- {
- observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, info->pixelBuffer, info->url.GetUrl(), info->preMultiplied));
- }
- else
- {
- observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, info->textureId, info->textureSet, (info->useAtlas == UseAtlas::USE_ATLAS) ? true : false, info->atlasRect, info->preMultiplied));
- }
+ EmitLoadComplete(observer, *info, success);
// Get the textureInfo from the container again as it may have been invalidated.
TextureCacheIndex textureInfoIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
return RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().GetGeometry(textureId, frontElements, backElements) : Geometry();
}
+void TextureManager::EmitLoadComplete(TextureUploadObserver* observer, TextureManager::TextureInfo& textureInfo, const bool& success)
+{
+ if(textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER)
+ {
+ observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, textureInfo.pixelBuffer, textureInfo.url.GetUrl(), textureInfo.preMultiplied));
+ }
+ else if(textureInfo.isAnimatedImageFormat)
+ {
+ observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::ANIMATED_IMAGE_TEXTURE, textureInfo.textureId, textureInfo.frameCount, textureInfo.frameInterval));
+ }
+ else
+ {
+ observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureInfo.textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied));
+ }
+}
+
} // namespace Internal
} // namespace Toolkit
* The parameters are used to specify how the animated image is loaded.
* The observer has the LoadComplete method called when the load is ready.
*
- * @param[in] animatedImageLoading The AnimatedImageLoading that contain the animated image information
- * @param[in] frameIndex The frame index to load.
- * @param[in] samplingMode The SamplingMode to use
- * @param[in] synchronousLoading true if the frame should be loaded synchronously
- * @param[out] textureId The textureId of the frame
- * @param[in] wrapModeU Horizontal Wrap mode
- * @param[in] wrapModeV Vertical Wrap mode
- * @param[in] textureObserver The client object should inherit from this and provide the "UploadCompleted" virtual.
- * This is called when an image load completes (or fails).
+ * @param[in] animatedImageLoading The AnimatedImageLoading that contain the animated image information
+ * @param[in] frameIndex The frame index to load.
+ * @param[out] textureId The textureId of the frame
+ * @param[in] samplingMode The SamplingMode to use
+ * @param[in] wrapModeU Horizontal Wrap mode
+ * @param[in] wrapModeV Vertical Wrap mode
+ * @param[in] synchronousLoading true if the frame should be loaded synchronously
+ * @param[in] useCache true if this frame loading uses cache.
+ * @param[in] textureObserver The client object should inherit from this and provide the "LoadCompleted" virtual.
+ * This is called when an image load completes (or fails).
*
- * @return The texture set containing the frame of animated image, or empty if still loading.
+ * @return The texture set containing the frame of animated image, or empty if still loading.
*/
- TextureSet LoadAnimatedImageTexture(
- Dali::AnimatedImageLoading animatedImageLoading,
- const std::uint32_t& frameIndex,
- const Dali::SamplingMode::Type& samplingMode,
- const bool& synchronousLoading,
- TextureManager::TextureId& textureId,
- const Dali::WrapMode::Type& wrapModeU,
- const Dali::WrapMode::Type& wrapModeV,
- TextureUploadObserver* textureObserver);
+ TextureSet LoadAnimatedImageTexture(Dali::AnimatedImageLoading animatedImageLoading,
+ const uint32_t& frameIndex,
+ TextureManager::TextureId& textureId,
+ const Dali::SamplingMode::Type& samplingMode,
+ const Dali::WrapMode::Type& wrapModeU,
+ const Dali::WrapMode::Type& wrapModeV,
+ const bool& synchronousLoading,
+ const bool& useCache,
+ TextureUploadObserver* textureObserver);
/**
* @brief Requests an image load of the given URL to get PixelBuffer.
* @param[in] fittingMode The FittingMode to use
* @param[in] samplingMode The SamplingMode to use
* @param[in] synchronousLoading true if the URL should be loaded synchronously
- * @param[in] textureObserver The client object should inherit from this and provide the "UploadCompleted" virtual.
+ * @param[in] textureObserver The client object should inherit from this and provide the "LoadCompleted" virtual.
* This is called when an image load completes (or fails).
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
* @param[out] loadingStatus The loading status of the texture
* @param[in] wrapModeU Horizontal Wrap mode
* @param[in] wrapModeV Vertical Wrap mode
- * @param[in] textureObserver The client object should inherit from this and provide the "UploadCompleted" virtual.
+ * @param[in] textureObserver The client object should inherit from this and provide the "LoadCompleted" virtual.
* This is called when an image load completes (or fails).
* @param[in] atlasObserver This is used if the texture is atlased, and will be called instead of
- * textureObserver.UploadCompleted
+ * textureObserver.LoadCompleted
* @param[in] imageAtlasManager The atlas manager to use for atlasing textures
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in] reloadPolicy Forces a reload of the texture even if already cached
* @param[in] fittingMode The FittingMode to use
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
- * but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
- * @param[in] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
+ * but "useAtlasing" will be set to false in the "LoadCompleted" callback from the TextureManagerUploadObserver.
+ * @param[in] observer The client object should inherit from this and provide the "LoadCompleted" virtual.
* This is called when an image load completes (or fails).
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in] reloadPolicy Forces a reload of the texture even if already cached
* default is false.
* @return A TextureId to use as a handle to reference this Texture
*/
- TextureManager::TextureId RequestLoad(
+ TextureId RequestLoad(
const VisualUrl& url,
const ImageDimensions& desiredSize,
const Dali::FittingMode::Type& fittingMode,
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
* be loaded, and marked successful,
- * but "useAtlasing" will be set to false in the "UploadCompleted" callback from
+ * but "useAtlasing" will be set to false in the "LoadCompleted" callback from
* the TextureManagerUploadObserver.
* @param[in] cropToMask Only used with masking, this will crop the scaled image to the mask size.
* If false, then the mask will be scaled to fit the image before being applied.
- * @param[in] observer The client object should inherit from this and provide the "UploadCompleted"
+ * @param[in] observer The client object should inherit from this and provide the "LoadCompleted"
* virtual.
* This is called when an image load completes (or fails).
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* default is false.
* @return A TextureId to use as a handle to reference this Texture
*/
- TextureManager::TextureId RequestLoad(
+ TextureId RequestLoad(
const VisualUrl& url,
const TextureManager::TextureId& maskTextureId,
const float& contentScale,
* default is false.
* @return A TextureId to use as a handle to reference this mask Texture
*/
- TextureManager::TextureId RequestMaskLoad(
+ TextureId RequestMaskLoad(
const VisualUrl& maskUrl,
const bool& synchronousLoading = false);
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be
* loaded, and marked successful, but "useAtlasing" will be set to false in the
- * "UploadCompleted" callback from the TextureManagerUploadObserver.
+ * "LoadCompleted" callback from the TextureManagerUploadObserver.
* @param[in] cropToMask Whether to crop the target after masking, or scale the mask to the image before
* masking.
* @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU
- * @param[in] observer The client object should inherit from this and provide the "UploadCompleted"
+ * @param[in] observer The client object should inherit from this and provide the "LoadCompleted"
* virtual.
* This is called when an image load completes (or fails).
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in] frameIndex The frame index of a frame to be loaded frame
* @param[in] synchronousLoading True if the frame should be loaded synchronously. If you skip this parameter,
* default is false.
+ * @param[in] useCache True if the texture will be cached.
* @return A TextureId to use as a handle to reference this Texture
*/
- TextureManager::TextureId RequestLoadInternal(
+ TextureId RequestLoadInternal(
const VisualUrl& url,
const TextureManager::TextureId& maskTextureId,
const float& contentScale,
TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
Dali::AnimatedImageLoading animatedImageLoading,
const std::uint32_t& frameIndex,
- const bool& synchronousLoading);
+ const bool& synchronousLoading,
+ const bool& useCache);
/**
* @brief Load a new image synchronously.
*/
void NotifyObservers(TextureManager::TextureInfo& textureInfo, const bool& success);
+ /**
+ * Call LoadComplete to the observer.
+ * @param[in] observer The client object should inherit from this and provide the "LoadCompleted"
+ * @param[in] textureInfo The struct associated with this Texture
+ * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
+ */
+ void EmitLoadComplete(TextureUploadObserver* observer, TextureManager::TextureInfo& textureInfo, const bool& success);
+
public:
/**
* @brief Common method to handle loading completion.
storageType(StorageType::UPLOAD_TO_TEXTURE),
animatedImageLoading(animatedImageLoading),
frameIndex(frameIndex),
+ frameCount(0u),
+ frameInterval(0u),
useAtlas(useAtlas),
loadSynchronously(loadSynchronously),
cropToMask(cropToMask),
preMultiplyOnLoad(preMultiplyOnLoad),
preMultiplied(false)
{
+ isAnimatedImageFormat = (animatedImageLoading) ? true : false;
}
/**
Dali::SamplingMode::Type samplingMode : 3; ///< The requested SamplingMode
StorageType storageType; ///< CPU storage / GPU upload;
Dali::AnimatedImageLoading animatedImageLoading; ///< AnimatedImageLoading that contains animated image information.
- std::uint32_t frameIndex; ///< frame index that be loaded, in case of animated image
+ uint32_t frameIndex; ///< Frame index that be loaded, in case of animated image
+ uint32_t frameCount; ///< Total frame count of input animated image. If this variable is not 0, this textureInfo is for animated image file format.
+ uint32_t frameInterval; ///< Time interval between this frame and next frame of animated image.
UseAtlas useAtlas; ///< USE_ATLAS if an atlas was requested.
bool loadSynchronously : 1; ///< True if synchronous loading was requested
bool orientationCorrection : 1; ///< True if the image should be rotated to match exif orientation data
bool preMultiplyOnLoad : 1; ///< True if the image's color should be multiplied by it's alpha
bool preMultiplied : 1; ///< True if the image's color was multiplied by it's alpha
+ bool isAnimatedImageFormat : 1; ///< true if the image is requested from animated image visual.
};
} // namespace TextureManagerType
{
}
+TextureUploadObserver::TextureInformation::TextureInformation(ReturnType returnType, int32_t textureId, uint32_t frameCount, uint32_t interval)
+: returnType(returnType),
+ textureId(textureId),
+ textureSet(),
+ useAtlasing(false),
+ atlasRect(Vector4::ZERO),
+ preMultiplied(false),
+ pixelBuffer(),
+ url(),
+ frameCount(frameCount),
+ interval(interval)
+{
+}
+
TextureUploadObserver::TextureUploadObserver()
{
}
enum class ReturnType
{
- TEXTURE = 0,
- PIXEL_BUFFER
+ PIXEL_BUFFER = 0,
+ TEXTURE,
+ ANIMATED_IMAGE_TEXTURE
};
struct TextureInformation
{
TextureInformation(ReturnType returnType, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied);
TextureInformation(ReturnType returnType, Devel::PixelBuffer pixelBuffer, const std::string& url, bool preMultiplied);
+ TextureInformation(ReturnType returnType, int32_t textureId, uint32_t frameCount, uint32_t interval);
TextureInformation();
bool preMultiplied; ///< True if the image had pre-multiplied alpha applied
Devel::PixelBuffer pixelBuffer; ///< The PixelBuffer of the loaded image.
std::string_view url; ///< The url address of the loaded image.
+ uint32_t frameCount{0}; ///< The frameCount of the animated image
+ uint32_t interval{0}; ///< Time interval between currently loaded frame and next frame.
};
public:
DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, MIRRORED_REPEAT)
DALI_ENUM_TO_STRING_TABLE_END(WRAP_MODE)
-const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
-constexpr auto LOOP_FOREVER = -1;
+// load policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN(LOAD_POLICY)
+ DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE)
+ DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED)
+DALI_ENUM_TO_STRING_TABLE_END(LOAD_POLICY)
+
+// release policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN(RELEASE_POLICY)
+ DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED)
+ DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED)
+ DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER)
+DALI_ENUM_TO_STRING_TABLE_END(RELEASE_POLICY)
+
+static constexpr uint32_t SINGLE_IMAGE_COUNT = 1u;
+static constexpr uint32_t FIRST_FRAME_INDEX = 0u;
+static constexpr uint16_t MINIMUM_CACHESIZE = 1;
+static constexpr Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+static constexpr auto LOOP_FOREVER = -1;
+static constexpr auto FIRST_LOOP = 0u;
#if defined(DEBUG_ENABLED)
Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
*
* | New
* | DoSetProperties()
- * | LoadFirstBatch()
- * | new cache
- * | cache->LoadBatch()
+ * | OnInitialize()
+ * | CreateImageCache()
* |
* | DoSetOnScene()
* | PrepareTextureSet()
* | cache->FirstFrame()
- * | CreateRenderer() (Doesn't become ready until first frame loads)
- * | StartFirstFrame()
* |
* | FrameReady(textureSet)
- * | start first frame:
+ * | StartFirstFrame:
* | actor.AddRenderer
* | start timer
* | mRenderer.SetTextures(textureSet)
* | if front frame is ready,
* | mRenderer.SetTextures( front frame's texture )
* | else
- * | mWaitingForTexture=true
- * | cache->LoadBatch()
+ * | Waiting for frame ready.
* |
* | FrameReady(textureSet)
* | mRenderer.SetTextures(textureSet)
visual->InitializeAnimatedImage(imageUrl);
visual->SetProperties(properties);
- if(visual->mFrameCount > 0)
- {
- visual->LoadFirstBatch();
- }
-
visual->Initialize();
return visual;
visual->mFrameCount = imageUrls.Count();
visual->SetProperties(properties);
- if(visual->mFrameCount > 0)
- {
- visual->LoadFirstBatch();
- }
-
visual->Initialize();
return visual;
AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory));
visual->InitializeAnimatedImage(imageUrl);
- if(visual->mFrameCount > 0)
- {
- visual->LoadFirstBatch();
- }
-
visual->Initialize();
return visual;
void AnimatedImageVisual::InitializeAnimatedImage(const VisualUrl& imageUrl)
{
- mImageUrl = imageUrl;
+ mImageUrl = imageUrl;
mAnimatedImageLoading = AnimatedImageLoading::New(imageUrl.GetUrl(), imageUrl.IsLocalResource());
- mFrameCount = mAnimatedImageLoading.GetImageCount();
+}
+
+void AnimatedImageVisual::CreateImageCache()
+{
+ DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::CreateImageCache() batchSize:%d cacheSize:%d\n", mBatchSize, mCacheSize);
+
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+ if(mAnimatedImageLoading)
+ {
+ mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, *this, mCacheSize, mBatchSize, IsSynchronousLoadingRequired());
+ }
+ else if(mImageUrls)
+ {
+ // Ensure the batch size and cache size are no bigger than the number of URLs,
+ // and that the cache is at least as big as the batch size.
+ uint16_t numUrls = mImageUrls->size();
+ uint16_t batchSize = std::max(std::min(mBatchSize, numUrls), MINIMUM_CACHESIZE);
+ uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE);
+ if(cacheSize < numUrls)
+ {
+ mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, cacheSize, batchSize, mFrameDelay);
+ }
+ else
+ {
+ mImageCache = new FixedImageCache(textureManager, *mImageUrls, *this, batchSize, mFrameDelay);
+ }
+ }
+
+ if(!mImageCache)
+ {
+ DALI_LOG_ERROR("mImageCache is null\n");
+ }
}
AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory)
mImageUrl(),
mAnimatedImageLoading(),
mFrameIndexForJumpTo(0),
+ mCurrentFrameIndex(FIRST_FRAME_INDEX),
mImageUrls(NULL),
mImageCache(NULL),
mCacheSize(2),
mBatchSize(2),
mFrameDelay(100),
mLoopCount(LOOP_FOREVER),
- mCurrentLoopIndex(0),
- mUrlIndex(0),
+ mCurrentLoopIndex(FIRST_LOOP),
+ mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED),
+ mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED),
mFrameCount(0),
mImageSize(),
mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
AnimatedImageVisual::~AnimatedImageVisual()
{
+ // AnimatedImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
+ // If this is animated image, clear cache. Else if this is single frame image, this is affected be release policy.
+ if(mFrameCount > SINGLE_IMAGE_COUNT || mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER)
+ {
+ mImageCache->ClearCache();
+ }
delete mImageCache;
delete mImageUrls;
}
map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast<int>(mFrameDelay));
map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast<int>(mLoopCount));
map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetCurrentFrameIndex()) : -1);
- map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetTotalFrameCount()) : -1);
+ map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>((mAnimatedImageLoading) ? mAnimatedImageLoading.GetImageCount() :
+ mImageCache->GetTotalFrameCount()) : -1);
map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior);
+
+ map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
+ map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
}
void AnimatedImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
// STOP reset functionality will actually be done in a future change
// Stop will be executed on next timer tick
mActionStatus = DevelAnimatedImageVisual::Action::STOP;
+ mCurrentLoopIndex = FIRST_LOOP;
if(IsOnScene())
{
DisplayNextFrame();
{
DoSetProperty(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second);
}
+ else if(keyValue.first == LOAD_POLICY_NAME)
+ {
+ DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second);
+ }
+ else if(keyValue.first == RELEASE_POLICY_NAME)
+ {
+ DoSetProperty(Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second);
+ }
+ else if(keyValue.first == SYNCHRONOUS_LOADING)
+ {
+ DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
+ }
}
}
+ // Load image immediately if LOAD_POLICY requires it
+ if(mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE)
+ {
+ PrepareTextureSet();
+ }
}
void AnimatedImageVisual::DoSetProperty(Property::Index index,
if(value.Get(frameDelay))
{
mFrameDelay = frameDelay;
+ if(mImageCache)
+ {
+ mImageCache->SetInterval(static_cast<uint32_t>(mFrameDelay));
+ }
}
break;
}
}
break;
}
+
+ case Toolkit::ImageVisual::Property::RELEASE_POLICY:
+ {
+ int releasePolicy = 0;
+ Scripting::GetEnumerationProperty(value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy);
+ mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type(releasePolicy);
+ break;
+ }
+
+ case Toolkit::ImageVisual::Property::LOAD_POLICY:
+ {
+ int loadPolicy = 0;
+ Scripting::GetEnumerationProperty(value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy);
+ mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy);
+ break;
+ }
}
}
void AnimatedImageVisual::DoSetOnScene(Actor& actor)
{
+ mStartFirstFrame = true;
mPlacementActor = actor;
- TextureSet textureSet = PrepareTextureSet();
-
- // Loading animated image file is failed.
- if(!mImageCache ||
- (mAnimatedImageLoading && !mAnimatedImageLoading.HasLoadingSucceeded()))
- {
- textureSet = SetLoadingFailed();
- }
-
- if(textureSet) // if the image loading is successful
- {
- StartFirstFrame(textureSet);
- }
- else
- {
- mStartFirstFrame = true;
- }
+ PrepareTextureSet();
}
void AnimatedImageVisual::DoSetOffScene(Actor& actor)
}
actor.RemoveRenderer(mImpl->mRenderer);
+ if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
+ {
+ mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
+ mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
+
+ TextureSet textureSet = TextureSet::New();
+ mImpl->mRenderer.SetTextures(textureSet);
+ }
+
mPlacementActor.Reset();
mStartFirstFrame = false;
+ mCurrentFrameIndex = FIRST_FRAME_INDEX;
+ mCurrentLoopIndex = FIRST_LOOP;
}
void AnimatedImageVisual::OnSetTransform()
}
}
+Shader AnimatedImageVisual::GenerateShader() const
+{
+ bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
+ Shader shader;
+ shader = mImageVisualShaderFactory.GetShader(
+ mFactoryCache,
+ ImageVisualShaderFeature::FeatureBuilder()
+ .ApplyDefaultTextureWrapMode(defaultWrapMode)
+ .EnableRoundedCorner(IsRoundedCornerRequired())
+ .EnableBorderline(IsBorderlineRequired()));
+ return shader;
+}
+
void AnimatedImageVisual::OnInitialize()
{
+ CreateImageCache();
+
bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
Shader shader = GenerateShader();
}
}
-void AnimatedImageVisual::LoadFirstBatch()
-{
- // Ensure the batch size and cache size are no bigger than the number of URLs,
- // and that the cache is at least as big as the batch size.
- uint16_t numUrls = 0;
- uint16_t batchSize = 1;
- uint16_t cacheSize = 1;
-
- if(mImageUrls)
- {
- numUrls = mImageUrls->size();
- }
- else
- {
- numUrls = mFrameCount;
- }
-
- batchSize = std::min(mBatchSize, numUrls);
- cacheSize = std::min(std::max(batchSize, mCacheSize), numUrls);
-
- DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadFirstBatch() batchSize:%d cacheSize:%d\n", batchSize, cacheSize);
-
- mUrlIndex = 0;
- TextureManager& textureManager = mFactoryCache.GetTextureManager();
-
- if(mAnimatedImageLoading)
- {
- mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, mFrameCount, *this, cacheSize, batchSize, IsSynchronousLoadingRequired());
- }
- else if(mImageUrls)
- {
- if(batchSize > 0 && cacheSize > 0)
- {
- if(cacheSize < numUrls)
- {
- mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, cacheSize, batchSize);
- }
- else
- {
- mImageCache = new FixedImageCache(textureManager, *mImageUrls, *this, batchSize);
- }
- }
- else
- {
- mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, 1, 1);
- }
- }
-
- if(!mImageCache)
- {
- DALI_LOG_ERROR("mImageCache is null\n");
- }
-}
-
-void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet)
+void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval)
{
DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::StartFirstFrame()\n");
}
}
- if(mFrameCount > 1)
+ if(mImpl->mResourceStatus != Toolkit::Visual::ResourceStatus::FAILED)
{
- int frameDelay = mImageCache->GetFrameInterval(0);
- if(frameDelay == 0u)
+ if(mFrameCount > SINGLE_IMAGE_COUNT)
{
- frameDelay = mFrameDelay; // from URL array
+ mFrameDelayTimer = Timer::New(firstInterval);
+ mFrameDelayTimer.TickSignal().Connect(this, &AnimatedImageVisual::DisplayNextFrame);
+ mFrameDelayTimer.Start();
}
- mFrameDelayTimer = Timer::New(frameDelay);
- mFrameDelayTimer.TickSignal().Connect(this, &AnimatedImageVisual::DisplayNextFrame);
- mFrameDelayTimer.Start();
- }
- if(mImpl->mResourceStatus != Toolkit::Visual::ResourceStatus::FAILED)
- {
DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::READY)\n");
ResourceReady(Toolkit::Visual::ResourceStatus::READY);
}
+
+ mCurrentFrameIndex = FIRST_FRAME_INDEX;
}
-TextureSet AnimatedImageVisual::PrepareTextureSet()
+void AnimatedImageVisual::PrepareTextureSet()
{
TextureSet textureSet;
if(mImageCache)
textureSet = mImageCache->FirstFrame();
}
+ // Check whether synchronous loading is true or false for the first frame.
if(textureSet)
{
SetImageSize(textureSet);
}
-
- return textureSet;
}
void AnimatedImageVisual::SetImageSize(TextureSet& textureSet)
}
}
-void AnimatedImageVisual::FrameReady(TextureSet textureSet)
+void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval)
{
// When image visual requested to load new frame to mImageCache and it is failed.
- if(!textureSet)
+ if(!mImageCache || !textureSet)
{
textureSet = SetLoadingFailed();
}
-
SetImageSize(textureSet);
if(mStartFirstFrame)
{
- StartFirstFrame(textureSet);
+ mFrameCount = mImageCache->GetTotalFrameCount();
+ StartFirstFrame(textureSet, interval);
}
else
{
if(mImpl->mRenderer)
{
+ if(mFrameDelayTimer && interval > 0u)
+ {
+ mFrameDelayTimer.SetInterval(interval);
+ }
mImpl->mRenderer.SetTextures(textureSet);
}
}
if(mImageCache)
{
- bool nextFrame = false;
uint32_t frameIndex = mImageCache->GetCurrentFrameIndex();
if(mIsJumpTo)
}
else if(mActionStatus == DevelAnimatedImageVisual::Action::STOP)
{
- frameIndex = 0;
+ mCurrentLoopIndex = FIRST_LOOP;
if(mStopBehavior == DevelImageVisual::StopBehavior::FIRST_FRAME)
{
- frameIndex = 0;
+ frameIndex = FIRST_FRAME_INDEX;
}
else if(mStopBehavior == DevelImageVisual::StopBehavior::LAST_FRAME)
{
}
else
{
- if(mFrameCount > 1)
+ if(mFrameCount > SINGLE_IMAGE_COUNT)
{
- nextFrame = true;
frameIndex++;
if(frameIndex >= mFrameCount)
{
- frameIndex %= mFrameCount;
+ frameIndex = FIRST_FRAME_INDEX;
++mCurrentLoopIndex;
}
return DisplayNextFrame();
}
}
-
- unsigned int delay = mImageCache->GetFrameInterval(frameIndex);
- if(delay > 0u)
- {
- if(mFrameDelayTimer.GetInterval() != delay)
- {
- mFrameDelayTimer.SetInterval(delay);
- }
- }
}
DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::DisplayNextFrame(this:%p) CurrentFrameIndex:%d\n", this, frameIndex);
- if(nextFrame)
- {
- textureSet = mImageCache->NextFrame();
- }
- else
- {
- textureSet = mImageCache->Frame(frameIndex);
- }
-
- continueTimer = (mActionStatus == DevelAnimatedImageVisual::Action::PLAY) ? true : false;
- }
+ textureSet = mImageCache->Frame(frameIndex);
- if(textureSet)
- {
- SetImageSize(textureSet);
- if(mImpl->mRenderer)
+ if(textureSet)
{
- mImpl->mRenderer.SetTextures(textureSet);
+ SetImageSize(textureSet);
+ if(mImpl->mRenderer)
+ {
+ mImpl->mRenderer.SetTextures(textureSet);
+ }
+ mFrameDelayTimer.SetInterval(mImageCache->GetFrameInterval(frameIndex));
}
+
+ mCurrentFrameIndex = frameIndex;
+ continueTimer = (mActionStatus == DevelAnimatedImageVisual::Action::PLAY && textureSet) ? true : false;
}
return continueTimer;
return textureSet;
}
-Shader AnimatedImageVisual::GenerateShader() const
-{
- bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
- Shader shader;
- shader = mImageVisualShaderFactory.GetShader(
- mFactoryCache,
- ImageVisualShaderFeature::FeatureBuilder()
- .ApplyDefaultTextureWrapMode(defaultWrapMode)
- .EnableRoundedCorner(IsRoundedCornerRequired())
- .EnableBorderline(IsBorderlineRequired()));
- return shader;
-}
-
} // namespace Internal
} // namespace Toolkit
private:
/**
- * Creates the renderer for the animated image
+ * @brief Initialize the animated image variables.
+ * @param[in] imageUrl The url of the animated image
*/
- void CreateRenderer();
+ void InitializeAnimatedImage(const VisualUrl& imageUrl);
/**
- * Starts the Load of the first batch of URLs
+ * @brief Create image cache for animated image or image array.
*/
- void LoadFirstBatch();
+ void CreateImageCache();
/**
- * Adds the texture set to the renderer, and the renderer to the
+ * @brief Adds the texture set to the renderer, and the renderer to the
* placement actor, and starts the frame timer
- * @param[in] textureSet The texture set to apply
+ * @param[in] textureSet The texture set to apply
+ * @param[in] firstInterval frame interval(ms) for the first frame.
*/
- void StartFirstFrame(TextureSet& textureSet);
+ void StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval);
/**
- * Prepares the texture set for displaying
+ * @brief Prepares the texture set for displaying
*/
- TextureSet PrepareTextureSet();
+ void PrepareTextureSet();
/**
- * Set the image size from the texture set
+ * @brief Set the image size from the texture set
* @param[in] textureSet The texture set to get the size from
*/
void SetImageSize(TextureSet& textureSet);
/**
- * Called when the next frame is ready.
+ * @brief Called when the next frame is ready.
* @param[in] textureSet the texture set to apply
+ * @param[in] interval interval(ms) for the frame
*/
- void FrameReady(TextureSet textureSet) override;
+ void FrameReady(TextureSet textureSet, uint32_t interval) override;
/**
- * Display the next frame. It is called when the mFrameDelayTimer ticks.
- * Returns true to ensure the timer continues running.
+ * @brief Display the next frame. It is called when the mFrameDelayTimer ticks.
+ * @return true to ensure the timer continues running.
*/
bool DisplayNextFrame();
/**
- * Initialize the animated image variables.
- * @param[in] imageUrl The url of the animated image
- */
- void InitializeAnimatedImage(const VisualUrl& imageUrl);
-
- /**
- * Set the state of loading fail of an image or a frame.
- * Returns TextureSet of broken image.
+ * @brief Set the state of loading fail of an image or a frame.
+ * @return TextureSet of broken image.
*/
TextureSet SetLoadingFailed();
VisualUrl mImageUrl;
Dali::AnimatedImageLoading mAnimatedImageLoading; // Only needed for animated image
uint32_t mFrameIndexForJumpTo; // Frame index into textureRects
+ uint32_t mCurrentFrameIndex;
// Variables for Multi-Image player
ImageCache::UrlList* mImageUrls;
uint16_t mFrameDelay;
int16_t mLoopCount;
int16_t mCurrentLoopIndex;
- uint16_t mUrlIndex;
+
+ // Variables for image visual policy.
+ Dali::Toolkit::ImageVisual::LoadPolicy::Type mLoadPolicy;
+ Dali::Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy;
// Shared variables
uint32_t mFrameCount; // Number of frames
// INTERNAL HEADERS
#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+// EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
namespace Dali
{
namespace Toolkit
{
namespace
{
-const bool ENABLE_ORIENTATION_CORRECTION(true);
+constexpr bool ENABLE_ORIENTATION_CORRECTION(true);
+constexpr uint32_t FIRST_FRAME_INDEX = 0u;
} // namespace
FixedImageCache::FixedImageCache(
- TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, unsigned int batchSize)
-: ImageCache(textureManager, observer, batchSize),
+ TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint32_t batchSize, uint32_t interval)
+: ImageCache(textureManager, observer, batchSize, interval),
mImageUrls(urlList),
- mFront(0u)
+ mFront(FIRST_FRAME_INDEX)
{
mReadyFlags.reserve(mImageUrls.size());
- LoadBatch();
}
FixedImageCache::~FixedImageCache()
{
- if(mTextureManagerAlive)
- {
- for(std::size_t i = 0; i < mImageUrls.size(); ++i)
- {
- mTextureManager.Remove(mImageUrls[i].mTextureId, this);
- }
- }
+ ClearCache();
}
TextureSet FixedImageCache::Frame(uint32_t frameIndex)
{
- while(frameIndex > mFront)
+ TextureSet textureSet;
+ if(frameIndex >= mImageUrls.size())
+ {
+ DALI_LOG_ERROR("Wrong frameIndex requested.\n");
+ return textureSet;
+ }
+
+ while(mReadyFlags.size() < mImageUrls.size() &&
+ (frameIndex > mFront || mReadyFlags.empty()))
{
++mFront;
- if(mFront >= mImageUrls.size())
- {
- mFront = 0;
- }
LoadBatch();
}
mFront = frameIndex;
- TextureSet textureSet;
- if(IsFrontReady() == true)
+ if(IsFrontReady() && mLoadState != TextureManager::LoadState::LOAD_FAILED)
{
textureSet = GetFrontTextureSet();
}
- else
- {
- mWaitingForReadyFrame = true;
- }
return textureSet;
}
TextureSet FixedImageCache::FirstFrame()
{
- TextureSet textureSet = GetFrontTextureSet();
-
- if(!textureSet)
- {
- mWaitingForReadyFrame = true;
- }
-
- return textureSet;
-}
-
-TextureSet FixedImageCache::NextFrame()
-{
- TextureSet textureSet = Frame((mFront + 1) % mImageUrls.size());
+ TextureSet textureSet = Frame(FIRST_FRAME_INDEX);
return textureSet;
}
uint32_t FixedImageCache::GetFrameInterval(uint32_t frameIndex) const
{
- return 0u;
+ return mInterval;
}
int32_t FixedImageCache::GetCurrentFrameIndex() const
void FixedImageCache::LoadBatch()
{
// Try and load up to mBatchSize images, until the cache is filled.
- // Once the cache is filled, mUrlIndex exceeds mImageUrls size and
- // no more images are loaded.
- bool frontFrameReady = IsFrontReady();
-
- for(unsigned int i = 0; i < mBatchSize && mUrlIndex < mImageUrls.size(); ++i)
+ // Once the cache is filled, no more images are loaded.
+ for(unsigned int i = 0; i < mBatchSize && mReadyFlags.size() < mImageUrls.size(); ++i)
{
- std::string& url = mImageUrls[mUrlIndex].mUrl;
+ uint32_t frameIndex = mReadyFlags.size();
+ std::string& url = mImageUrls[frameIndex].mUrl;
mReadyFlags.push_back(false);
// from within this method. This means it won't yet have a texture id, so we
// need to account for this inside the LoadComplete method using mRequestingLoad.
mRequestingLoad = true;
+ mLoadState = TextureManager::LoadState::LOADING;
bool synchronousLoading = false;
bool atlasingStatus = false;
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
mTextureManager.LoadTexture(
- url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[mUrlIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
+ url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[frameIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
- if(loadingStatus == false) // not loading, means it's already ready.
- {
- SetImageFrameReady(mImageUrls[mUrlIndex].mTextureId);
- }
mRequestingLoad = false;
- ++mUrlIndex;
- }
-
- CheckFrontFrame(frontFrameReady);
-}
-
-void FixedImageCache::SetImageFrameReady(TextureManager::TextureId textureId)
-{
- for(std::size_t i = 0; i < mImageUrls.size(); ++i)
- {
- if(mImageUrls[i].mTextureId == textureId)
- {
- mReadyFlags[i] = true;
- break;
- }
}
}
void FixedImageCache::CheckFrontFrame(bool wasReady)
{
- if(mWaitingForReadyFrame && wasReady == false && IsFrontReady())
+ if(wasReady == false && IsFrontReady())
{
- mWaitingForReadyFrame = false;
- mObserver.FrameReady(GetFrontTextureSet());
+ mObserver.FrameReady(GetFrontTextureSet(), mInterval);
}
}
-void FixedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
+void FixedImageCache::ClearCache()
{
- bool frontFrameReady = IsFrontReady();
-
- if(!mRequestingLoad)
+ if(mTextureManagerAlive)
{
- SetImageFrameReady(textureInformation.textureId);
+ for(std::size_t i = 0; i < mImageUrls.size(); ++i)
+ {
+ mTextureManager.Remove(mImageUrls[i].mTextureId, this);
+ mImageUrls[i].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+ }
+ }
+ mReadyFlags.clear();
+ mLoadState = TextureManager::LoadState::NOT_STARTED;
+}
+void FixedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
+{
+ if(loadSuccess)
+ {
+ mLoadState = TextureManager::LoadState::LOAD_FINISHED;
+ bool frontFrameReady = IsFrontReady();
+ if(!mRequestingLoad)
+ {
+ for(std::size_t i = 0; i < mImageUrls.size(); ++i)
+ {
+ if(mImageUrls[i].mTextureId == textureInformation.textureId)
+ {
+ mReadyFlags[i] = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ mReadyFlags.back() = true;
+ }
CheckFrontFrame(frontFrameReady);
}
else
{
- // LoadComplete has been called from within RequestLoad. TextureManager must
- // therefore already have the texture cached, so make the texture ready.
- // (Use the last texture, as the texture id hasn't been assigned yet)
- mReadyFlags.back() = true;
+ mLoadState = TextureManager::LoadState::LOAD_FAILED;
+ mObserver.FrameReady(TextureSet(), 0);
}
}
* @param[in] urlList List of urls to cache
* @param[in] observer FrameReady observer
* @param[in] batchSize The size of a batch to load
+ * @param[in] interval Time interval between each frame
*
* This will start loading textures immediately, according to the
* batch and cache sizes. The cache is as large as the number of urls.
FixedImageCache(TextureManager& textureManager,
UrlList& urlList,
ImageCache::FrameReadyObserver& observer,
- unsigned int batchSize);
+ uint32_t batchSize,
+ uint32_t interval);
~FixedImageCache() override;
/**
- * Get the Nth frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
+ * @copydoc Internal::ImageCache::Frame()
*/
TextureSet Frame(uint32_t frameIndex) override;
/**
- * Get the first frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
+ * @copydoc Internal::ImageCache::FirstFrame()
*/
TextureSet FirstFrame() override;
/**
- * Get the next frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
- */
- TextureSet NextFrame() override;
-
- /**
- * Get the interval of Nth frame.
+ * @copydoc Internal::ImageCache::GetFrameInterval()
*/
uint32_t GetFrameInterval(uint32_t frameIndex) const override;
/**
- * Get the current rendered frame index.
- * If there isn't any loaded frame, returns -1.
+ * @copydoc Internal::ImageCache::GetCurrentFrameIndex()
*/
int32_t GetCurrentFrameIndex() const override;
/**
- * Get total frame count of the animated image file.
+ * @copydoc Internal::ImageCache::GetTotalFrameCount()
*/
int32_t GetTotalFrameCount() const override;
+ /**
+ * @copydoc Internal::ImageCache::ClearCache()
+ */
+ void ClearCache() override;
+
private:
/**
+ * @brief Check whether the front frame is ready or not.
+ *
* @return true if the front frame is ready
*/
bool IsFrontReady() const;
/**
- * Load the next batch of images
+ * @brief Load the next batch of images
*/
void LoadBatch();
/**
- * Find the matching image frame, and set it to ready
- */
- void SetImageFrameReady(TextureManager::TextureId textureId);
-
- /**
- * Get the texture set of the front frame.
- * @return the texture set
+ * @brief Get the texture set of the front frame.
+ *
+ * @return the texture set of the front of Cache.
*/
TextureSet GetFrontTextureSet() const;
/**
- * Check if the front frame has become ready - if so, inform observer
+ * @brief Check if the front frame has become ready - if so, inform observer
+ *
* @param[in] wasReady Readiness before call.
*/
void CheckFrontFrame(bool wasReady);
protected:
+ /**
+ * @copydoc Toolkit::TextureUploadObserver::LoadComplete()
+ */
void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override;
private:
- std::vector<UrlStore>& mImageUrls;
- std::vector<bool> mReadyFlags;
- unsigned int mFront;
+ std::vector<UrlStore>& mImageUrls;
+ std::vector<bool> mReadyFlags;
+ std::vector<TextureManager::LoadState> mLoadStates;
+ uint32_t mFront;
};
} //namespace Internal
{
ImageCache::ImageCache(TextureManager& textureManager,
ImageCache::FrameReadyObserver& observer,
- unsigned int batchSize)
+ uint32_t batchSize,
+ uint32_t interval)
: mTextureManager(textureManager),
mObserver(observer),
mBatchSize(batchSize),
- mUrlIndex(0u),
- mWaitingForReadyFrame(false),
+ mInterval(interval),
+ mLoadState(TextureManager::LoadState::NOT_STARTED),
mRequestingLoad(false),
mTextureManagerAlive(true)
{
mTextureManagerAlive = false;
}
+void ImageCache::SetInterval(uint32_t interval)
+{
+ mInterval = interval;
+}
+
} //namespace Internal
} //namespace Toolkit
} //namespace Dali
{
public:
/**
- * Informs observer when the next texture set is ready to display
+ * @brief Informs observer when the next texture set is ready to display
* @param[in] textureSet The ready texture set
+ * @param[in] interval interval(ms) for the frame
*/
- virtual void FrameReady(TextureSet textureSet) = 0;
+ virtual void FrameReady(TextureSet textureSet, uint32_t interval) = 0;
};
struct UrlStore
public:
/**
- * Constructor.
+ * @brief Constructor.
* @param[in] textureManager The texture manager
* @param[in] urlList List of urls to cache
* @param[in] observer FrameReady observer
* @param[in] batchSize The size of a batch to load
+ * @param[in] interval Time interval(ms) between each frame
*
* This will start loading textures immediately, according to the
* batch and cache sizes. The cache is as large as the number of urls.
*/
ImageCache(TextureManager& textureManager,
ImageCache::FrameReadyObserver& observer,
- unsigned int batchSize);
+ uint32_t batchSize,
+ uint32_t interval);
virtual ~ImageCache();
/**
- * Get the first frame. If it's not ready, this will trigger the
+ * @brief Get the first frame. If it's not ready, this will trigger the
* sending of FrameReady() when the image becomes ready.
+ *
+ * @return TextureSet of the first frame.
*/
virtual TextureSet FirstFrame() = 0;
/**
- * Get the next frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
- */
- virtual TextureSet NextFrame() = 0;
-
- /**
- * Get the Nth frame. If it's not ready, this will trigger the
+ * @brief Get the Nth frame. If it's not ready, this will trigger the
* sending of FrameReady() when the image becomes ready.
+ *
+ * @param[in] frameIndex required frame index to be returned.
+ * @return TextureSet of the frame index.
*/
virtual TextureSet Frame(uint32_t frameIndex) = 0;
/**
- * Get the interval of Nth frame.
+ * @brief Get the interval(ms) of Nth frame.
+ *
+ * @param[in] frameIndex frame index to get frame interval.
+ * @return Time interval in millisecond between frames of frameIndex and frameIndex + 1.
*/
virtual uint32_t GetFrameInterval(uint32_t frameIndex) const = 0;
/**
- * Get the current rendered frame index.
+ * @brief Get the current rendered frame index.
* If there isn't any loaded frame, returns -1.
+ *
+ * @return Frame index of currently showing frame.
*/
virtual int32_t GetCurrentFrameIndex() const = 0;
/**
- * Get total frame count of the animated image file.
+ * @brief Get total frame count of the animated image file.
+ *
+ * @return Total frame count of the animated image file.
*/
virtual int32_t GetTotalFrameCount() const = 0;
+ /**
+ * @brief Clears animated image cache and remove loaded textures.
+ */
+ virtual void ClearCache() = 0;
+
+ /**
+ * @brief Set default interval(ms) between each frame.
+ *
+ * @param[in] interval time interval in millisecond to be used as default interval.
+ */
+ virtual void SetInterval(uint32_t interval);
+
private:
/**
- * Called before the texture manager is destroyed.
+ * @brief Called before the texture manager is destroyed.
*/
void TextureManagerDestroyed() final;
protected:
- TextureManager& mTextureManager;
- FrameReadyObserver& mObserver;
- unsigned int mBatchSize;
- unsigned int mUrlIndex;
- bool mWaitingForReadyFrame : 1;
- bool mRequestingLoad : 1;
- bool mTextureManagerAlive : 1;
+ TextureManager& mTextureManager;
+ FrameReadyObserver& mObserver;
+ uint32_t mBatchSize;
+ uint32_t mInterval;
+ TextureManager::LoadState mLoadState;
+ bool mRequestingLoad : 1;
+ bool mTextureManagerAlive : 1;
};
} //namespace Internal
// CLASS HEADER
#include "rolling-animated-image-cache.h"
-// EXTERNAL HEADERS
-
// INTERNAL HEADERS
#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
#define LOG_CACHE
#endif
-const bool ENABLE_ORIENTATION_CORRECTION(true);
+static constexpr bool ENABLE_ORIENTATION_CORRECTION(true);
} // namespace
{
namespace Internal
{
+namespace
+{
+static constexpr uint32_t SINGLE_IMAGE_COUNT = 1u;
+static constexpr uint32_t FIRST_FRAME_INDEX = 0u;
+} // namespace
+
RollingAnimatedImageCache::RollingAnimatedImageCache(
- TextureManager& textureManager, AnimatedImageLoading& animatedImageLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, bool isSynchronousLoading)
-: ImageCache(textureManager, observer, batchSize),
+ TextureManager& textureManager, AnimatedImageLoading& animatedImageLoading, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, bool isSynchronousLoading)
+: ImageCache(textureManager, observer, batchSize, 0u),
mAnimatedImageLoading(animatedImageLoading),
- mFrameCount(frameCount),
- mFrameIndex(0),
+ mFrameCount(SINGLE_IMAGE_COUNT),
+ mFrameIndex(FIRST_FRAME_INDEX),
mCacheSize(cacheSize),
mQueue(cacheSize),
- mIsSynchronousLoading(isSynchronousLoading),
- mOnLoading(false)
+ mIsSynchronousLoading(isSynchronousLoading)
{
mImageUrls.resize(mFrameCount);
mIntervals.assign(mFrameCount, 0);
- LoadBatch();
}
RollingAnimatedImageCache::~RollingAnimatedImageCache()
{
- if(mTextureManagerAlive)
- {
- while(!mQueue.IsEmpty())
- {
- ImageFrame imageFrame = mQueue.PopFront();
- mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this);
- }
- }
+ ClearCache();
+ mAnimatedImageLoading.Reset();
}
TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex)
}
TextureSet textureSet;
+ uint32_t batchFrameIndex = frameIndex;
// If we need to load new frame that are not stored in queue.
// Load the frame synchronously.
+ bool synchronouslyLoaded = false;
if(mIsSynchronousLoading && mQueue.IsEmpty())
{
- bool synchronousLoading = true;
- textureSet = mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading, frameIndex, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, mImageUrls[frameIndex].mTextureId, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this);
- mFrameIndex = (frameIndex + 1) % mFrameCount;
+ textureSet = RequestFrameLoading(frameIndex, frameIndex == FIRST_FRAME_INDEX, true);
+ batchFrameIndex = (frameIndex + 1) % mFrameCount;
+ uint32_t interval = 0u;
+ if(textureSet)
+ {
+ synchronouslyLoaded = true;
+ interval = mAnimatedImageLoading.GetFrameInterval(mQueue.Back().mFrameNumber);
+ }
+ MakeFrameReady(synchronouslyLoaded, textureSet, interval);
}
- if(popExist || mQueue.IsEmpty())
+ if(popExist || mQueue.IsEmpty() || synchronouslyLoaded)
{
// If the frame of frameIndex was already loaded, load batch from the last frame of queue
if(!mQueue.IsEmpty())
{
if(!mLoadWaitingQueue.empty())
{
- mFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount;
+ batchFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount;
}
else
{
- mFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount;
+ batchFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount;
}
}
else
{
- mOnLoading = false;
// If the request is for the first frame or a jumped frame(JUMP_TO) remove current waiting queue.
mLoadWaitingQueue.clear();
// If the queue is empty, and the frame of frameIndex is not loaded synchronously. load batch from the frame of frameIndex
if(!textureSet)
{
- mFrameIndex = frameIndex;
+ batchFrameIndex = frameIndex;
}
}
- LoadBatch();
+ LoadBatch(batchFrameIndex);
}
- if(!textureSet)
+ if(!textureSet && mLoadState != TextureManager::LoadState::LOAD_FAILED && IsFrontReady() == true)
{
- if(IsFrontReady() == true)
- {
- textureSet = GetFrontTextureSet();
- }
- else
- {
- mWaitingForReadyFrame = true;
- }
+ textureSet = GetFrontTextureSet();
}
return textureSet;
TextureSet RollingAnimatedImageCache::FirstFrame()
{
- return Frame(0u);
-}
-
-TextureSet RollingAnimatedImageCache::NextFrame()
-{
- TextureSet textureSet;
- if(!mQueue.IsEmpty())
- {
- uint32_t frameIndex = mQueue.Front().mFrameNumber;
- if(IsFrontReady())
- {
- frameIndex = (frameIndex + 1) % mFrameCount;
- }
- textureSet = Frame(frameIndex);
- }
- else
- {
- DALI_LOG_ERROR("Cache is empty.");
- }
-
+ TextureSet textureSet = Frame(FIRST_FRAME_INDEX);
return textureSet;
}
uint32_t RollingAnimatedImageCache::GetFrameInterval(uint32_t frameIndex) const
{
- return mAnimatedImageLoading.GetFrameInterval(frameIndex);
+ if(frameIndex >= mIntervals.size())
+ {
+ return 0u;
+ }
+ return mIntervals[frameIndex];
}
int32_t RollingAnimatedImageCache::GetCurrentFrameIndex() const
return (!mQueue.IsEmpty() && mQueue.Front().mReady);
}
-void RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex)
+TextureSet RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex, bool useCache, bool synchronousLoading)
{
ImageFrame imageFrame;
imageFrame.mFrameNumber = frameIndex;
mQueue.PushBack(imageFrame);
- mRequestingLoad = true;
+ mLoadState = TextureManager::LoadState::LOADING;
+
+ TextureManager::TextureId loadTextureId = TextureManager::INVALID_TEXTURE_ID;
+ TextureSet textureSet = mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading,
+ frameIndex,
+ loadTextureId,
+ SamplingMode::BOX_THEN_LINEAR,
+ Dali::WrapMode::Type::DEFAULT,
+ Dali::WrapMode::Type::DEFAULT,
+ synchronousLoading,
+ useCache,
+ this);
- bool synchronousLoading = false;
- mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading, frameIndex, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, mImageUrls[frameIndex].mTextureId, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this);
+ mImageUrls[frameIndex].mTextureId = loadTextureId;
- mRequestingLoad = false;
+ return textureSet;
}
-void RollingAnimatedImageCache::LoadBatch()
+void RollingAnimatedImageCache::LoadBatch(uint32_t frameIndex)
{
// Try and load up to mBatchSize images, until the cache is filled.
// Once the cache is filled, as frames progress, the old frame is
// removed, and another frame is loaded
-
- bool frontFrameReady = IsFrontReady();
- for(unsigned int i = 0; i < mBatchSize && mQueue.Count() + mLoadWaitingQueue.size() < static_cast<uint32_t>(mCacheSize) && !mQueue.IsFull(); ++i)
+ uint32_t minimumSize = std::min(mCacheSize, mFrameCount);
+ for(uint32_t i = 0; i < mBatchSize && (mQueue.Count() + mLoadWaitingQueue.size()) < minimumSize; ++i)
{
- if(!mOnLoading)
+ if(mLoadState != TextureManager::LoadState::LOADING)
{
- mOnLoading = true;
- RequestFrameLoading(mFrameIndex);
+ RequestFrameLoading(frameIndex, frameIndex == FIRST_FRAME_INDEX, false);
}
else
{
- mLoadWaitingQueue.push_back(mFrameIndex);
+ mLoadWaitingQueue.push_back(frameIndex);
}
- mFrameIndex++;
- mFrameIndex %= mFrameCount;
+ frameIndex++;
+ frameIndex %= mFrameCount;
}
- CheckFrontFrame(frontFrameReady);
-
LOG_CACHE;
}
return mImageUrls[mQueue[index].mFrameNumber].mTextureId;
}
-void RollingAnimatedImageCache::CheckFrontFrame(bool wasReady)
+void RollingAnimatedImageCache::ClearCache()
{
- if(mWaitingForReadyFrame && wasReady == false && IsFrontReady())
+ while(mTextureManagerAlive && !mQueue.IsEmpty())
{
- mWaitingForReadyFrame = false;
- mObserver.FrameReady(GetFrontTextureSet());
+ ImageFrame imageFrame = mQueue.PopFront();
+ mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this);
+ mImageUrls[imageFrame.mFrameNumber].mTextureId = TextureManager::INVALID_TEXTURE_ID;
}
+ mLoadWaitingQueue.clear();
+ mLoadState = TextureManager::LoadState::NOT_STARTED;
}
-void RollingAnimatedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
+void RollingAnimatedImageCache::MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval)
{
- DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId);
- LOG_CACHE;
-
- bool frontFrameReady = IsFrontReady();
-
- if(!mRequestingLoad)
+ if(!loadSuccess)
{
- SetImageFrameReady(textureInformation.textureId);
-
- CheckFrontFrame(frontFrameReady);
+ mLoadState = TextureManager::LoadState::LOAD_FAILED;
+ mObserver.FrameReady(TextureSet(), 0);
}
else
{
- // LoadComplete has been called from within RequestLoad. TextureManager must
- // therefore already have the texture cached, so make the texture ready.
- // (Use the last texture, as the texture id hasn't been assigned yet)
- mQueue.Back().mReady = true;
+ mLoadState = TextureManager::LoadState::LOAD_FINISHED;
+
+ // Reset size of Queue according to the real frame count.
+ if(mFrameCount != mAnimatedImageLoading.GetImageCount())
+ {
+ mFrameCount = mAnimatedImageLoading.GetImageCount();
+ mImageUrls.resize(mFrameCount);
+ mIntervals.assign(mFrameCount, 0u);
+ }
+
+ bool frontFrameReady = IsFrontReady();
+ // Because only one frame is on loading and the others are in mLoadWaitingQueue,
+ // mQueue.Back() is always the frame currently loaded.
+ mQueue.Back().mReady = true;
+ mIntervals[mQueue.Back().mFrameNumber] = interval;
+ // Check whether currently loaded frame is front of queue or not.
+ // If it is, notify frame ready to observer.
+ if(frontFrameReady == false && IsFrontReady())
+ {
+ mObserver.FrameReady(textureSet, interval);
+ }
}
+}
- mOnLoading = false;
- // The frames of a single animated image can not be loaded parallelly.
- // Therefore, a frame is now loading, other orders are waiting.
- // And, after the frame is loaded, requests load of next order.
- if(!mLoadWaitingQueue.empty())
+void RollingAnimatedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
+{
+ DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId);
+ LOG_CACHE;
+
+ MakeFrameReady(loadSuccess, mTextureManager.GetTextureSet(textureInformation.textureId), textureInformation.interval);
+
+ if(loadSuccess)
{
- uint32_t loadingIndex = mLoadWaitingQueue.front();
- mLoadWaitingQueue.erase(mLoadWaitingQueue.begin());
- mOnLoading = true;
- RequestFrameLoading(loadingIndex);
+ // The frames of a single animated image can not be loaded parallelly.
+ // Therefore, a frame is now loading, other orders are waiting.
+ // And, after the frame is loaded, requests load of next order.
+ if(!mLoadWaitingQueue.empty())
+ {
+ uint32_t loadingIndex = mLoadWaitingQueue.front();
+ mLoadWaitingQueue.erase(mLoadWaitingQueue.begin());
+ RequestFrameLoading(loadingIndex, loadingIndex == FIRST_FRAME_INDEX, false);
+ }
+ else if(mQueue.Count() == 1u && textureInformation.frameCount > SINGLE_IMAGE_COUNT)
+ {
+ // There is only an image in queue and no waiting queue.
+ // Request to load batch once again.
+ uint32_t batchFrameIndex = 0u;
+ if(!mLoadWaitingQueue.empty())
+ {
+ batchFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount;
+ }
+ else
+ {
+ batchFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount;
+ }
+ LoadBatch(batchFrameIndex);
+ }
}
LOG_CACHE;
{
public:
/**
- * Constructor.
+ * @brief Constructor.
* @param[in] textureManager The texture manager
* @param[in] animatedImageLoader The loaded animated image
- * @param[in] frameCount The number of frames in the animated image
* @param[in] observer FrameReady observer
* @param[in] cacheSize The size of the cache
* @param[in] batchSize The size of a batch to load
*/
RollingAnimatedImageCache(TextureManager& textureManager,
AnimatedImageLoading& animatedImageLoader,
- uint32_t frameCount,
ImageCache::FrameReadyObserver& observer,
uint16_t cacheSize,
uint16_t batchSize,
bool isSynchronousLoading);
/**
- * Destructor
+ * @brief Destructor
*/
~RollingAnimatedImageCache() override;
/**
- * Get the Nth frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
+ * @copydoc Internal::ImageCache::Frame()
*/
TextureSet Frame(uint32_t frameIndex) override;
/**
- * Get the first frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
+ * @copydoc Internal::ImageCache::FirstFrame()
*/
TextureSet FirstFrame() override;
/**
- * Get the next frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
- */
- TextureSet NextFrame() override;
-
- /**
- * Get the interval of Nth frame.
+ * @copydoc Internal::ImageCache::GetFrameInterval()
*/
uint32_t GetFrameInterval(uint32_t frameIndex) const override;
/**
- * Get the current rendered frame index.
- * If there isn't any loaded frame, returns -1.
+ * @copydoc Internal::ImageCache::GetCurrentFrameIndex()
*/
int32_t GetCurrentFrameIndex() const override;
/**
- * Get total frame count of the animated image file.
+ * @copydoc Internal::ImageCache::GetTotalFrameCount()
*/
int32_t GetTotalFrameCount() const override;
+ /**
+ * @copydoc Internal::ImageCache::ClearCache()
+ */
+ void ClearCache() override;
+
private:
/**
+ * @brief Check whether the front frame is ready or not.
+ *
* @return true if the front frame is ready
*/
bool IsFrontReady() const;
/**
- * Request to Load a frame
+ * @brief Request to Load a frame
+ *
+ * @param[in] frameIndex index of frame to be loaded.
+ * @param[in] useCache true if this frame loading uses cache.
+ * @param[in] synchronousLoading true if the frame should be loaded synchronously
+ *
+ * @return the texture set currently loaded.
*/
- void RequestFrameLoading(uint32_t frameIndex);
+ TextureSet RequestFrameLoading(uint32_t frameIndex, bool useCache, bool synchronousLoading);
/**
- * Load the next batch of images
+ * @brief Load the next batch of images
+ *
+ * @param[in] frameIndex starting frame index of batch to be loaded.
*/
- void LoadBatch();
+ void LoadBatch(uint32_t frameIndex);
/**
- * Find the matching image frame, and set it to ready
+ * @brief Find the matching image frame, and set it to ready
+ *
+ * @param[in] textureId texture id to be marked as ready.
*/
void SetImageFrameReady(TextureManager::TextureId textureId);
/**
- * Get the texture set of the front frame.
- * @return the texture set
+ * @brief Get the texture set of the front frame.
+ *
+ * @return the texture set of the front of Cache.
*/
TextureSet GetFrontTextureSet() const;
/**
- * Get the texture id of the given index
+ * @brief Get the texture id of the given index
+ *
+ * @param[in] index index of the queue.
*/
TextureManager::TextureId GetCachedTextureId(int index) const;
/**
- * Check if the front frame has become ready - if so, inform observer
- * @param[in] wasReady Readiness before call.
+ * @brief Make the loaded frame ready and notify it to the texture upload observer
+ *
+ * @param[in] loadSuccess whether the loading is succeded or not.
+ * @param[in] textureSet textureSet for this frame.
+ * @param[in] interval interval between this frame and next frame.
*/
- void CheckFrontFrame(bool wasReady);
+ void MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval);
protected:
+ /**
+ * @copydoc Toolkit::TextureUploadObserver::LoadComplete()
+ */
void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override;
private:
+
/**
* Secondary class to hold readiness and index into url
*/
struct ImageFrame
{
- unsigned int mFrameNumber = 0u;
- bool mReady = false;
+ uint32_t mFrameNumber = 0u;
+ bool mReady = false;
};
Dali::AnimatedImageLoading mAnimatedImageLoading;
uint32_t mFrameCount;
- int mFrameIndex;
- int mCacheSize;
+ uint32_t mFrameIndex;
+ uint32_t mCacheSize;
std::vector<UrlStore> mImageUrls;
std::vector<int32_t> mIntervals;
std::vector<uint32_t> mLoadWaitingQueue;
CircularQueue<ImageFrame> mQueue;
bool mIsSynchronousLoading;
- bool mOnLoading;
};
} // namespace Internal
#define LOG_CACHE
#endif
-const bool ENABLE_ORIENTATION_CORRECTION(true);
+static constexpr bool ENABLE_ORIENTATION_CORRECTION(true);
+
+static constexpr uint32_t FIRST_FRAME_INDEX = 0u;
} // namespace
namespace Internal
{
RollingImageCache::RollingImageCache(
- TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize)
-: ImageCache(textureManager, observer, batchSize),
+ TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, uint32_t interval)
+: ImageCache(textureManager, observer, batchSize, interval),
mImageUrls(urlList),
mQueue(cacheSize)
{
- LoadBatch();
}
RollingImageCache::~RollingImageCache()
{
- if(mTextureManagerAlive)
- {
- while(!mQueue.IsEmpty())
- {
- ImageFrame imageFrame = mQueue.PopFront();
- mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
- }
- }
+ ClearCache();
}
TextureSet RollingImageCache::Frame(uint32_t frameIndex)
{
- // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures.
- if(mImageUrls[frameIndex].mTextureId == TextureManager::INVALID_TEXTURE_ID)
+ // Pop frames until the frame of frameIndex become front frame.
+ bool popExist = false;
+ while(!mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex)
{
- mUrlIndex = frameIndex;
- while(!mQueue.IsEmpty())
- {
- ImageFrame imageFrame = mQueue.PopFront();
- mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
- mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
- }
- LoadBatch();
+ ImageFrame imageFrame = mQueue.PopFront();
+ mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
+ mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+ popExist = true;
}
- // If the frame is already loaded, remove previous frames of the frame in the queue
- // and load new frames amount of removed frames.
- else
+
+ // TODO: synchronous loading of first frame.
+ if(popExist || mQueue.IsEmpty())
{
- bool popExist = false;
- while(!mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex)
- {
- ImageFrame imageFrame = mQueue.PopFront();
- mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
- mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
- popExist = true;
- }
- if(popExist)
+ uint32_t batchFrameIndex = frameIndex;
+ // If the frame of frameIndex was already loaded, load batch from the last frame of queue
+ if(!mQueue.IsEmpty())
{
- mUrlIndex = (mQueue.Back().mUrlIndex + 1) % mImageUrls.size();
- LoadBatch();
+ batchFrameIndex = (mQueue.Back().mUrlIndex + 1) % mImageUrls.size();
}
+ LoadBatch(batchFrameIndex);
}
TextureSet textureSet;
- if(IsFrontReady() == true)
+ if(IsFrontReady() == true && mLoadState != TextureManager::LoadState::LOAD_FAILED)
{
textureSet = GetFrontTextureSet();
}
- else
- {
- mWaitingForReadyFrame = true;
- }
return textureSet;
}
TextureSet RollingImageCache::FirstFrame()
{
- return Frame(0u);
-}
-
-TextureSet RollingImageCache::NextFrame()
-{
- TextureSet textureSet;
- if(!mQueue.IsEmpty())
- {
- uint32_t frameIndex = mQueue.Front().mUrlIndex;
- if(IsFrontReady())
- {
- frameIndex = (frameIndex + 1) % mImageUrls.size();
- }
- textureSet = Frame(frameIndex);
- }
- else
- {
- DALI_LOG_ERROR("Cache is empty.");
- }
-
+ TextureSet textureSet = Frame(FIRST_FRAME_INDEX);
return textureSet;
}
uint32_t RollingImageCache::GetFrameInterval(uint32_t frameIndex) const
{
- return 0u;
+ return mInterval;
}
int32_t RollingImageCache::GetCurrentFrameIndex() const
return (!mQueue.IsEmpty() && mQueue.Front().mReady);
}
-void RollingImageCache::LoadBatch()
+void RollingImageCache::LoadBatch(uint32_t frameIndex)
{
// Try and load up to mBatchSize images, until the cache is filled.
// Once the cache is filled, as frames progress, the old frame is
// cleared, but not erased, and another image is loaded
- bool frontFrameReady = IsFrontReady();
-
for(unsigned int i = 0; i < mBatchSize && !mQueue.IsFull(); ++i)
{
ImageFrame imageFrame;
- std::string& url = mImageUrls[mUrlIndex].mUrl;
- imageFrame.mUrlIndex = mUrlIndex;
+ std::string& url = mImageUrls[frameIndex].mUrl;
+ imageFrame.mUrlIndex = frameIndex;
imageFrame.mReady = false;
- ++mUrlIndex;
- mUrlIndex %= mImageUrls.size();
-
mQueue.PushBack(imageFrame);
// Note, if the image is already loaded, then LoadComplete will get called
// from within this method. This means it won't yet have a texture id, so we
// need to account for this inside the LoadComplete method using mRequestingLoad.
mRequestingLoad = true;
+ mLoadState = TextureManager::LoadState::LOADING;
bool synchronousLoading = false;
bool atlasingStatus = false;
Dali::ImageDimensions textureRectSize;
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- mTextureManager.LoadTexture(
- url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[imageFrame.mUrlIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
+ TextureManager::TextureId loadTextureId = TextureManager::INVALID_TEXTURE_ID;
+ TextureSet textureSet = mTextureManager.LoadTexture(
+ url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, loadTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
+ mImageUrls[imageFrame.mUrlIndex].mTextureId = loadTextureId;
mRequestingLoad = false;
- }
- CheckFrontFrame(frontFrameReady);
-}
-
-void RollingImageCache::SetImageFrameReady(TextureManager::TextureId textureId)
-{
- for(std::size_t i = 0; i < mQueue.Count(); ++i)
- {
- if(GetCachedTextureId(i) == textureId)
- {
- mQueue[i].mReady = true;
- break;
- }
+ ++frameIndex;
+ frameIndex %= mImageUrls.size();
}
}
return mImageUrls[mQueue[index].mUrlIndex].mTextureId;
}
-void RollingImageCache::CheckFrontFrame(bool wasReady)
+void RollingImageCache::ClearCache()
{
- if(mWaitingForReadyFrame && wasReady == false && IsFrontReady())
+ while(mTextureManagerAlive && !mQueue.IsEmpty())
{
- mWaitingForReadyFrame = false;
- mObserver.FrameReady(GetFrontTextureSet());
+ ImageFrame imageFrame = mQueue.PopFront();
+ mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
+ mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
}
+ mLoadState = TextureManager::LoadState::NOT_STARTED;
}
void RollingImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId);
LOG_CACHE;
- bool frontFrameReady = IsFrontReady();
-
- if(!mRequestingLoad)
+ if(loadSuccess)
{
- SetImageFrameReady(textureInformation.textureId);
+ mLoadState = TextureManager::LoadState::LOAD_FINISHED;
+ bool frontFrameReady = IsFrontReady();
+ if(!mRequestingLoad)
+ {
+ for(std::size_t i = 0; i < mQueue.Count(); ++i)
+ {
+ if(GetCachedTextureId(i) == textureInformation.textureId)
+ {
+ mQueue[i].mReady = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // LoadComplete has been called from within RequestLoad. TextureManager must
+ // therefore already have the texture cached, so make the texture ready.
+ // (Use the last texture, as the texture id hasn't been assigned yet)
+ mQueue.Back().mReady = true;
+ }
- CheckFrontFrame(frontFrameReady);
+ if(!frontFrameReady && IsFrontReady())
+ {
+ mObserver.FrameReady(mTextureManager.GetTextureSet(textureInformation.textureId), mInterval);
+ }
}
else
{
- // LoadComplete has been called from within RequestLoad. TextureManager must
- // therefore already have the texture cached, so make the texture ready.
- // (Use the last texture, as the texture id hasn't been assigned yet)
- mQueue.Back().mReady = true;
+ mLoadState = TextureManager::LoadState::LOAD_FAILED;
+ mObserver.FrameReady(TextureSet(), 0);
}
LOG_CACHE;
* @param[in] observer FrameReady observer
* @param[in] cacheSize The size of the cache
* @param[in] batchSize The size of a batch to load
+ * @param[in] interval Time interval between each frame
*
* This will start loading textures immediately, according to the
* batch and cache sizes.
UrlList& urlList,
ImageCache::FrameReadyObserver& observer,
uint16_t cacheSize,
- uint16_t batchSize);
+ uint16_t batchSize,
+ uint32_t interval);
/**
* Destructor
~RollingImageCache() override;
/**
- * Get the Nth frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
+ * @copydoc Internal::ImageCache::Frame()
*/
TextureSet Frame(uint32_t frameIndex) override;
/**
- * Get the first frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
+ * @copydoc Internal::ImageCache::FirstFrame()
*/
TextureSet FirstFrame() override;
/**
- * Get the next frame. If it's not ready, this will trigger the
- * sending of FrameReady() when the image becomes ready.
- */
- TextureSet NextFrame() override;
-
- /**
- * Get the interval of Nth frame.
+ * @copydoc Internal::ImageCache::GetFrameInterval()
*/
uint32_t GetFrameInterval(uint32_t frameIndex) const override;
/**
- * Get the current rendered frame index.
- * If there isn't any loaded frame, returns -1.
+ * @copydoc Internal::ImageCache::GetCurrentFrameIndex()
*/
int32_t GetCurrentFrameIndex() const override;
/**
- * Get total frame count of the animated image file.
+ * @copydoc Internal::ImageCache::GetTotalFrameCount()
*/
int32_t GetTotalFrameCount() const override;
-private:
/**
- * @return true if the front frame is ready
+ * @copydoc Internal::ImageCache::ClearCache()
*/
- bool IsFrontReady() const;
+ void ClearCache() override;
+private:
/**
- * Load the next batch of images
+ * @brief Check whether the front frame is ready or not.
+ *
+ * @return true if the front frame is ready
*/
- void LoadBatch();
+ bool IsFrontReady() const;
/**
- * Find the matching image frame, and set it to ready
+ * @brief Load the next batch of images
+ *
+ * @param[in] frameIndex starting frame index of batch to be loaded.
*/
- void SetImageFrameReady(TextureManager::TextureId textureId);
+ void LoadBatch(uint32_t frameIndex);
/**
- * Get the texture set of the front frame.
- * @return the texture set
+ * @brief Get the texture set of the front frame.
+ *
+ * @return the texture set of the front of Cache.
*/
TextureSet GetFrontTextureSet() const;
/**
- * Get the texture id of the given index
+ * @brief Get the texture id of the given index
+ *
+ * @param[in] index index of the queue.
*/
TextureManager::TextureId GetCachedTextureId(int index) const;
/**
- * Check if the front frame has become ready - if so, inform observer
+ * @brief Check if the front frame has become ready - if so, inform observer
+ *
* @param[in] wasReady Readiness before call.
*/
void CheckFrontFrame(bool wasReady);
protected:
+ /**
+ * @copydoc Toolkit::TextureUploadObserver::LoadComplete()
+ */
void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override;
private:
bool mReady = false;
};
- std::vector<UrlStore>& mImageUrls;
- CircularQueue<ImageFrame> mQueue;
+ std::vector<UrlStore>& mImageUrls;
+ CircularQueue<ImageFrame> mQueue;
};
} // namespace Internal
}
}
-bool ImageVisual::IsResourceReady() const
-{
- return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
- mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED);
-}
-
void ImageVisual::UpdateShader()
{
if(mImpl->mRenderer)
void OnSetTransform() override;
/**
- * @copydoc Visual::Base::IsResourceReady
- */
- bool IsResourceReady() const override;
-
- /**
* @copydoc Visual::Base::UpdateShader
*/
void UpdateShader() override;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
mCroppedWidth(0),
mCroppedHeight(0),
mBorder(0, 0, 0, 0),
- mLoadingState(LoadingState::LOADING),
+ mLoadingState(LoadingState::NOT_STARTED),
mPreMultiplyOnLoad(false),
mRenderingMap{nullptr}
{
mLoadingState = LoadingState::LOAD_COMPLETE;
}
+void NPatchData::NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess)
+{
+ observer->LoadComplete(
+ loadSuccess,
+ TextureUploadObserver::TextureInformation(
+ TextureUploadObserver::ReturnType::TEXTURE,
+ static_cast<TextureManager::TextureId>(mId), ///< Note : until end of NPatchLoader::Load, npatch-visual don't know the id of data.
+ mTextureSet,
+ false, // UseAtlas
+ Vector4(), // AtlasRect
+ mPreMultiplyOnLoad));
+}
+
void NPatchData::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
{
if(loadSuccess)
{
- SetLoadedNPatchData(textureInformation.pixelBuffer, textureInformation.preMultiplied);
+ if(mLoadingState != LoadingState::LOAD_COMPLETE)
+ {
+ // If mLoadingState is LOAD_FAILED, just re-set (It can be happened when sync loading is failed, but async loading is succeeded).
+ SetLoadedNPatchData(textureInformation.pixelBuffer, textureInformation.preMultiplied);
+ }
}
else
{
- mLoadingState = LoadingState::LOAD_FAILED;
+ if(mLoadingState == LoadingState::LOADING)
+ {
+ mLoadingState = LoadingState::LOAD_FAILED;
+ }
+ // If mLoadingState is already LOAD_COMPLETE, we can use uploaded texture (It can be happened when sync loading is succeeded, but async loading is failed).
+ else if(mLoadingState == LoadingState::LOAD_COMPLETE)
+ {
+ loadSuccess = true;
+ }
}
for(uint32_t index = 0; index < mObserverList.Count(); ++index)
{
TextureUploadObserver* observer = mObserverList[index];
- observer->LoadComplete(loadSuccess, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, TextureManager::INVALID_TEXTURE_ID, mTextureSet, false, Vector4(), textureInformation.preMultiplied));
+ NotifyObserver(observer, loadSuccess);
}
+
+ mObserverList.Clear();
}
} // namespace Internal
*/
enum class LoadingState
{
- LOADING = 0, ///< NPatch is on loading.
- LOAD_COMPLETE, ///< NPatch loading is completed successfully.
- LOAD_FAILED ///< NPatch loading is failed.
+ NOT_STARTED = 0, ///< NPatch loading is not started yet.
+ LOADING, ///< NPatch is on loading.
+ LOAD_COMPLETE, ///< NPatch loading is completed successfully.
+ LOAD_FAILED ///< NPatch loading is failed.
};
public:
*/
void SetLoadedNPatchData(Devel::PixelBuffer& pixelBuffer, bool preMultiplied);
+ /**
+ * @brief Send LoadComplete notify with current setuped NPatchData
+ *
+ * @param [in] observer observer who will be got LoadComplete notify
+ * @param [in] loadSuccess whether the image load success or not.
+ */
+ void NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess);
+
private:
/**
* @copydoc TextureUploadObserver::LoadComplete
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
std::size_t NPatchLoader::Load(TextureManager& textureManager, TextureUploadObserver* textureObserver, const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad, bool synchronousLoading)
{
- std::size_t hash = CalculateHash(url.GetUrl());
- OwnerContainer<NPatchData*>::SizeType index = UNINITIALIZED_ID;
- const OwnerContainer<NPatchData*>::SizeType count = mCache.Count();
+ NPatchData* data = GetNPatchData(url, border, preMultiplyOnLoad);
- for(; index < count; ++index)
+ DALI_ASSERT_ALWAYS(data && "NPatchData creation failed!");
+
+ if(data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
{
- if(mCache[index]->GetHash() == hash)
+ if(!synchronousLoading)
{
- // hash match, check url as well in case of hash collision
- if(mCache[index]->GetUrl().GetUrl() == url.GetUrl())
+ // NotifyObserver already done, so
+ // data will not iterate observer list.
+ // We need to call LoadComplete directly.
+ data->NotifyObserver(textureObserver, true);
+ }
+ }
+ else // if NOT_STARTED or LOADING or LOAD_FAILED, try to reload.
+ {
+ if(!synchronousLoading)
+ {
+ data->AddObserver(textureObserver);
+ // If still LOADING and async, don't need to request reload. Fast return.
+ if(data->GetLoadingState() == NPatchData::LoadingState::LOADING)
{
- // Use cached data
- if(mCache[index]->GetBorder() == border)
- {
- if(mCache[index]->GetLoadingState() == NPatchData::LoadingState::LOADING)
- {
- mCache[index]->AddObserver(textureObserver);
- }
- return mCache[index]->GetId(); // valid indices are from 1 onwards
- }
- else
- {
- if(mCache[index]->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
- {
- // Same url but border is different - use the existing texture
- NPatchData* newData = new NPatchData();
- newData->SetId(GenerateUniqueNPatchDataId());
- newData->SetHash(hash);
- newData->SetUrl(url);
- newData->SetCroppedWidth(mCache[index]->GetCroppedWidth());
- newData->SetCroppedHeight(mCache[index]->GetCroppedHeight());
-
- newData->SetTextures(mCache[index]->GetTextures());
-
- NPatchUtility::StretchRanges stretchRangesX;
- stretchRangesX.PushBack(Uint16Pair(border.left, ((newData->GetCroppedWidth() >= static_cast<unsigned int>(border.right)) ? newData->GetCroppedHeight() - border.right : 0)));
-
- NPatchUtility::StretchRanges stretchRangesY;
- stretchRangesY.PushBack(Uint16Pair(border.top, ((newData->GetCroppedWidth() >= static_cast<unsigned int>(border.bottom)) ? newData->GetCroppedHeight() - border.bottom : 0)));
+ return data->GetId();
+ }
+ }
- newData->SetStretchPixelsX(stretchRangesX);
- newData->SetStretchPixelsY(stretchRangesY);
- newData->SetBorder(border);
+ data->SetLoadingState(NPatchData::LoadingState::LOADING);
- newData->SetPreMultiplyOnLoad(mCache[index]->IsPreMultiplied());
+ auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
+ : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- newData->SetLoadingState(NPatchData::LoadingState::LOAD_COMPLETE);
- newData->AddObserver(textureObserver);
+ Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(url, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, data, true, preMultiplyOnLoading);
- mCache.PushBack(newData);
- return newData->GetId(); // valid ids start from 1u
- }
- }
- }
+ if(pixelBuffer)
+ {
+ preMultiplyOnLoad = (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false;
+ data->SetLoadedNPatchData(pixelBuffer, preMultiplyOnLoad);
+ }
+ else if(synchronousLoading)
+ {
+ data->SetLoadingState(NPatchData::LoadingState::LOAD_FAILED);
}
- }
-
- // If this is new image loading, make new cache data
- NPatchData* data;
- data = new NPatchData();
- data->SetId(GenerateUniqueNPatchDataId());
- data->SetHash(hash);
- data->SetUrl(url);
- data->SetBorder(border);
- data->SetPreMultiplyOnLoad(preMultiplyOnLoad);
- data->AddObserver(textureObserver);
- mCache.PushBack(data);
-
- auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
- : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-
- Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(url, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, data, true, preMultiplyOnLoading);
-
- if(pixelBuffer)
- {
- preMultiplyOnLoad = (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false;
- data->SetLoadedNPatchData(pixelBuffer, preMultiplyOnLoad);
}
return data->GetId();
}
int32_t NPatchLoader::GetCacheIndexFromId(const NPatchData::NPatchDataId id)
{
- const unsigned int size = mCache.Count();
+ const unsigned int size = mCache.size();
for(unsigned int i = 0; i < size; ++i)
{
- if(mCache[i]->GetId() == id)
+ if(mCache[i].mData->GetId() == id)
{
return i;
}
int32_t cacheIndex = GetCacheIndexFromId(id);
if(cacheIndex != INVALID_CACHE_INDEX)
{
- data = mCache[cacheIndex];
+ data = mCache[cacheIndex].mData;
return true;
}
data = nullptr;
return;
}
- NPatchData* data;
- data = mCache[cacheIndex];
+ NPatchInfo& info(mCache[cacheIndex]);
- data->RemoveObserver(textureObserver);
+ info.mData->RemoveObserver(textureObserver);
- if(data->GetObserverCount() == 0)
+ if(--info.mReferenceCount <= 0)
{
- mCache.Erase(mCache.Begin() + cacheIndex);
+ mCache.erase(mCache.begin() + cacheIndex);
}
}
+NPatchData* NPatchLoader::GetNPatchData(const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad)
+{
+ std::size_t hash = CalculateHash(url.GetUrl());
+ std::vector<NPatchInfo>::size_type index = UNINITIALIZED_ID;
+ const std::vector<NPatchInfo>::size_type count = mCache.size();
+
+ NPatchInfo* infoPtr = nullptr;
+
+ for(; index < count; ++index)
+ {
+ if(mCache[index].mData->GetHash() == hash)
+ {
+ // hash match, check url as well in case of hash collision
+ if(mCache[index].mData->GetUrl().GetUrl() == url.GetUrl())
+ {
+ // Use cached data. Need to fast-out return.
+ if(mCache[index].mData->GetBorder() == border)
+ {
+ mCache[index].mReferenceCount++;
+ return mCache[index].mData;
+ }
+ else
+ {
+ if(mCache[index].mData->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ // If we only found LOAD_FAILED case, replace current data. We can reuse texture
+ if(infoPtr == nullptr || infoPtr->mData->GetLoadingState() != NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ infoPtr = &mCache[index];
+ }
+ }
+ // Still loading pixel buffer. We cannot reuse cached texture yet. Skip checking
+ else if(mCache[index].mData->GetLoadingState() == NPatchData::LoadingState::LOADING)
+ {
+ continue;
+ }
+ // if LOAD_FAILED, reuse this cached NPatchData, and try to load again.
+ else
+ {
+ if(infoPtr == nullptr)
+ {
+ infoPtr = &mCache[index];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If this is new image loading, make new cache data
+ if(infoPtr == nullptr)
+ {
+ NPatchInfo info(new NPatchData());
+ info.mData->SetId(GenerateUniqueNPatchDataId());
+ info.mData->SetHash(hash);
+ info.mData->SetUrl(url);
+ info.mData->SetBorder(border);
+ info.mData->SetPreMultiplyOnLoad(preMultiplyOnLoad);
+
+ mCache.emplace_back(std::move(info));
+ infoPtr = &mCache.back();
+ }
+ // Else if LOAD_COMPLETE, Same url but border is different - use the existing texture
+ else if(infoPtr->mData->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ NPatchInfo info(new NPatchData());
+
+ info.mData->SetId(GenerateUniqueNPatchDataId());
+ info.mData->SetHash(hash);
+ info.mData->SetUrl(url);
+ info.mData->SetCroppedWidth(infoPtr->mData->GetCroppedWidth());
+ info.mData->SetCroppedHeight(infoPtr->mData->GetCroppedHeight());
+
+ info.mData->SetTextures(infoPtr->mData->GetTextures());
+
+ NPatchUtility::StretchRanges stretchRangesX;
+ stretchRangesX.PushBack(Uint16Pair(border.left, ((info.mData->GetCroppedWidth() >= static_cast<unsigned int>(border.right)) ? info.mData->GetCroppedHeight() - border.right : 0)));
+
+ NPatchUtility::StretchRanges stretchRangesY;
+ stretchRangesY.PushBack(Uint16Pair(border.top, ((info.mData->GetCroppedWidth() >= static_cast<unsigned int>(border.bottom)) ? info.mData->GetCroppedHeight() - border.bottom : 0)));
+
+ info.mData->SetStretchPixelsX(stretchRangesX);
+ info.mData->SetStretchPixelsY(stretchRangesY);
+ info.mData->SetBorder(border);
+
+ info.mData->SetPreMultiplyOnLoad(infoPtr->mData->IsPreMultiplied());
+
+ info.mData->SetLoadingState(NPatchData::LoadingState::LOAD_COMPLETE);
+
+ mCache.emplace_back(std::move(info));
+ infoPtr = &mCache.back();
+ }
+ // Else, LOAD_FAILED. just increase reference so we can reuse it.
+ else
+ {
+ infoPtr->mReferenceCount++;
+ }
+
+ DALI_ASSERT_ALWAYS(infoPtr && "NPatchInfo creation failed!");
+
+ return infoPtr->mData;
+}
+
} // namespace Internal
} // namespace Toolkit
// EXTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-#include <dali/devel-api/common/owner-container.h>
#include <dali/public-api/rendering/texture-set.h>
#include <string>
/**
* @brief Remove a texture matching id.
- * Erase the observer from the observer list of cache.
- * If the observer list is empty, the textureSet will be reset.
+ * Erase the observer from the observer list of cache if we need.
+ * This API decrease cached NPatchInfo reference.
+ * If the NPatchInfo reference become 0, the textureSet will be reset.
*
* @param [in] id cache data id
* @param [in] textureObserver The NPatchVisual that requested loading.
int32_t GetCacheIndexFromId(const NPatchData::NPatchDataId id);
+private:
+ /**
+ * @brief Information of NPatchData
+ * It also hold ownership of NPatchData memory.
+ */
+ struct NPatchInfo
+ {
+ NPatchInfo(NPatchData* data)
+ : mData(data),
+ mReferenceCount(1u)
+ {
+ }
+ ~NPatchInfo()
+ {
+ if(mData)
+ {
+ delete mData;
+ }
+ }
+ NPatchInfo(NPatchInfo&& info) // move constructor
+ {
+ mData = std::move(info.mData);
+ mReferenceCount = info.mReferenceCount;
+ info.mData = nullptr;
+ info.mReferenceCount = 0u;
+ }
+ NPatchInfo& operator=(NPatchInfo&& info) // move operator
+ {
+ mData = std::move(info.mData);
+ mReferenceCount = info.mReferenceCount;
+ info.mData = nullptr;
+ info.mReferenceCount = 0u;
+ return *this;
+ }
+
+ NPatchInfo() = delete; // Do not use default constructor
+ NPatchInfo(const NPatchInfo& info) = delete; // Do not use copy constructor
+
+ NPatchData* mData;
+ std::int16_t mReferenceCount; ///< The number of N-patch visuals that use this data.
+ };
+
+ /**
+ * @brief Get cached NPatchData by inputed url and border. If there is no cached data, create new one.
+ * @note This API increase cached NPatchInfo reference.
+ *
+ * @param [in] url to retrieve
+ * @param [in] border The border size of the image
+ * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+ * image has no alpha channel
+ * @return NPatchData pointer that Load function will used.
+ */
+ NPatchData* GetNPatchData(const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad);
+
protected:
/**
* Undefined copy constructor.
NPatchLoader& operator=(const NPatchLoader& rhs);
private:
- NPatchData::NPatchDataId mCurrentNPatchDataId;
- OwnerContainer<NPatchData*> mCache;
+ NPatchData::NPatchDataId mCurrentNPatchDataId;
+ std::vector<NPatchInfo> mCache;
};
} // namespace Internal
// Load the auxiliary image
auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
mAuxiliaryPixelBuffer = textureManager.LoadPixelBuffer(mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, this, true, preMultiplyOnLoading);
+
+ // If synchronousLoading is true, we can check the auxiliaryResource's status now.
+ if(synchronousLoading)
+ {
+ mAuxiliaryResourceStatus = mAuxiliaryPixelBuffer ? Toolkit::Visual::ResourceStatus::READY : Toolkit::Visual::ResourceStatus::FAILED;
+ }
}
}
// load when first go on stage
LoadImages();
+ // Set mPlacementActor now, because some case, LoadImages can use this information in LoadComplete API.
+ // at this case, we try to SetResouce to mPlaceActor twice. so, we should avoid that case.
+ mPlacementActor = actor;
+
const NPatchData* data;
- if(mLoader.GetNPatchData(mId, data))
+ if(mImpl->mRenderer && mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
{
- Geometry geometry = CreateGeometry();
- Shader shader = CreateShader();
-
- mImpl->mRenderer.SetGeometry(geometry);
- mImpl->mRenderer.SetShader(shader);
-
- mPlacementActor = actor;
- if(data->GetLoadingState() != NPatchData::LoadingState::LOADING)
+ // If mAuxiliaryUrl need to be loaded, we should wait it until LoadComplete called.
+ if(!mAuxiliaryUrl.IsValid() || mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::PREPARING)
{
- if(RenderingAddOn::Get().IsValid())
- {
- RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
- }
-
- ApplyTextureAndUniforms();
- actor.AddRenderer(mImpl->mRenderer);
- mPlacementActor.Reset();
-
- // npatch loaded and ready to display
- ResourceReady(Toolkit::Visual::ResourceStatus::READY);
+ SetResource();
}
}
}
mImageUrl(),
mAuxiliaryUrl(),
mId(NPatchData::INVALID_NPATCH_DATA_ID),
+ mAuxiliaryResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
mBorderOnly(false),
mBorder(),
mAuxiliaryImageAlpha(0.0f),
{
textureSet = data->GetTextures();
NPatchHelper::ApplyTextureAndUniforms(mImpl->mRenderer, data);
+
+ if(mAuxiliaryPixelBuffer)
+ {
+ // If the auxiliary image is smaller than the un-stretched NPatch, use CPU resizing to enlarge it to the
+ // same size as the unstretched NPatch. This will give slightly higher quality results than just relying
+ // on GL interpolation alone.
+ if(mAuxiliaryPixelBuffer.GetWidth() < data->GetCroppedWidth() &&
+ mAuxiliaryPixelBuffer.GetHeight() < data->GetCroppedHeight())
+ {
+ mAuxiliaryPixelBuffer.Resize(data->GetCroppedWidth(), data->GetCroppedHeight());
+ }
+
+ // Note, this resets mAuxiliaryPixelBuffer handle
+ auto auxiliaryPixelData = Devel::PixelBuffer::Convert(mAuxiliaryPixelBuffer);
+
+ auto texture = Texture::New(TextureType::TEXTURE_2D,
+ auxiliaryPixelData.GetPixelFormat(),
+ auxiliaryPixelData.GetWidth(),
+ auxiliaryPixelData.GetHeight());
+ texture.Upload(auxiliaryPixelData);
+
+ // TODO : This code exist due to the texture cache manager hold TextureSet, not Texture.
+ // If we call textureSet.SetTexture(1, texture) directly, the cached TextureSet also be changed.
+ // We should make pass utc-Dali-VisualFactory.cpp UtcDaliNPatchVisualAuxiliaryImage02().
+ TextureSet tempTextureSet = TextureSet::New();
+ tempTextureSet.SetTexture(0, textureSet.GetTexture(0));
+ tempTextureSet.SetTexture(1, texture);
+ textureSet = tempTextureSet;
+
+ mImpl->mRenderer.RegisterProperty(DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA,
+ AUXILIARY_IMAGE_ALPHA_NAME,
+ mAuxiliaryImageAlpha);
+ }
+ mImpl->mRenderer.SetTextures(textureSet);
}
else
{
DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str());
- textureSet = TextureSet::New();
-
Actor actor = mPlacementActor.GetHandle();
Vector2 imageSize = Vector2::ZERO;
if(actor)
{
imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
}
- mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+ mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize, false);
}
- if(mAuxiliaryPixelBuffer)
- {
- // If the auxiliary image is smaller than the un-stretched NPatch, use CPU resizing to enlarge it to the
- // same size as the unstretched NPatch. This will give slightly higher quality results than just relying
- // on GL interpolation alone.
- if(mAuxiliaryPixelBuffer.GetWidth() < data->GetCroppedWidth() &&
- mAuxiliaryPixelBuffer.GetHeight() < data->GetCroppedHeight())
- {
- mAuxiliaryPixelBuffer.Resize(data->GetCroppedWidth(), data->GetCroppedHeight());
- }
-
- // Note, this resets mAuxiliaryPixelBuffer handle
- auto auxiliaryPixelData = Devel::PixelBuffer::Convert(mAuxiliaryPixelBuffer);
-
- auto texture = Texture::New(TextureType::TEXTURE_2D,
- auxiliaryPixelData.GetPixelFormat(),
- auxiliaryPixelData.GetWidth(),
- auxiliaryPixelData.GetHeight());
- texture.Upload(auxiliaryPixelData);
- textureSet.SetTexture(1, texture);
- mImpl->mRenderer.RegisterProperty(DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA,
- AUXILIARY_IMAGE_ALPHA_NAME,
- mAuxiliaryImageAlpha);
- }
- mImpl->mRenderer.SetTextures(textureSet);
-
// Register transform properties
mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
}
mImpl->mRenderer.SetGeometry(geometry);
mImpl->mRenderer.SetShader(shader);
+ if(RenderingAddOn::Get().IsValid())
+ {
+ RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
+ }
Actor actor = mPlacementActor.GetHandle();
if(actor)
{
ApplyTextureAndUniforms();
actor.AddRenderer(mImpl->mRenderer);
mPlacementActor.Reset();
+ }
- // npatch loaded and ready to display
+ // npatch loaded and ready to display
+ if(data->GetLoadingState() != NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ }
+ else
+ {
ResourceReady(Toolkit::Visual::ResourceStatus::READY);
}
}
void NPatchVisual::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
{
- if(textureInformation.returnType == TextureUploadObserver::ReturnType::TEXTURE)
+ if(textureInformation.returnType == TextureUploadObserver::ReturnType::TEXTURE) // For the Url.
{
- EnablePreMultipliedAlpha(textureInformation.preMultiplied);
- if(!loadSuccess)
+ if(textureInformation.textureId != TextureManager::INVALID_TEXTURE_ID)
{
- // Image loaded and ready to display
- ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ if(mId == NPatchData::INVALID_NPATCH_DATA_ID)
+ {
+ // Special case when mLoader.Load call LoadComplete function before mId setup.
+ // We can overwrite mId.
+ mId = static_cast<NPatchData::NPatchDataId>(textureInformation.textureId);
+ }
}
-
- if(mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid())
+ if(loadSuccess)
{
- SetResource();
+ EnablePreMultipliedAlpha(textureInformation.preMultiplied);
}
}
- else // for the ReturnType::PIXEL_BUFFER
+ else // For the AuxiliaryUrl : ReturnType::PIXEL_BUFFER
{
if(loadSuccess && textureInformation.url == mAuxiliaryUrl.GetUrl())
{
- mAuxiliaryPixelBuffer = textureInformation.pixelBuffer;
- SetResource();
+ mAuxiliaryPixelBuffer = textureInformation.pixelBuffer;
+ mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::READY;
}
else
{
- // Image loaded and ready to display
- ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
+ }
+ }
+ // If auxiliaryUrl didn't required OR auxiliaryUrl load done.
+ if(!mAuxiliaryUrl.IsValid() || mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::PREPARING)
+ {
+ const NPatchData* data;
+ // and.. If Url loading done.
+ if(mImpl->mRenderer && mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
+ {
+ SetResource();
}
}
}
WeakHandle<Actor> mPlacementActor; ///< Weakhandle to contain Actor during texture loading
NPatchLoader& mLoader; ///< reference to N patch loader for fast access
ImageVisualShaderFactory& mImageVisualShaderFactory;
- VisualUrl mImageUrl; ///< The url to the N patch to load
- VisualUrl mAuxiliaryUrl; ///< An auxiliary image that can be displayed on top of the N-Patch
- NPatchData::NPatchDataId mId; ///< id of the N patch (from loader/cache)
- Devel::PixelBuffer mAuxiliaryPixelBuffer; ///< pixel buffer of the auxiliary mask image
- bool mBorderOnly; ///< if only border is desired
- Rect<int> mBorder; ///< The size of the border
- float mAuxiliaryImageAlpha; ///< The alpha value for the auxiliary image only
- Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy; ///< The release policy to determine when an image should no longer be cached.
+ VisualUrl mImageUrl; ///< The url to the N patch to load
+ VisualUrl mAuxiliaryUrl; ///< An auxiliary image that can be displayed on top of the N-Patch
+ NPatchData::NPatchDataId mId; ///< id of the N patch (from loader/cache)
+ Devel::PixelBuffer mAuxiliaryPixelBuffer; ///< pixel buffer of the auxiliary mask image
+ Toolkit::Visual::ResourceStatus mAuxiliaryResourceStatus; ///< resource status for auxiliary mask image
+ bool mBorderOnly; ///< if only border is desired
+ Rect<int> mBorder; ///< The size of the border
+ float mAuxiliaryImageAlpha; ///< The alpha value for the auxiliary image only
+ Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy; ///< The release policy to determine when an image should no longer be cached.
};
} // namespace Internal
}
}
-bool SvgVisual::IsResourceReady() const
-{
- return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
- mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED);
-}
-
void SvgVisual::UpdateShader()
{
if(mImpl->mRenderer)
#define DALI_TOOLKIT_INTERNAL_SVG_VISUAL_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
void OnSetTransform() override;
/**
- * @copydoc Visual::Base::IsResourceReady
- */
- bool IsResourceReady() const override;
-
- /**
* @copydoc Visual::Base::UpdateShader
*/
void UpdateShader() override;
bool Visual::Base::IsResourceReady() const
{
- return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY);
+ return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
+ mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED);
}
bool Visual::Base::IsSynchronousLoadingRequired() const
void ResourceReady(Toolkit::Visual::ResourceStatus resourceStatus);
/**
- * @brief Called when the visuals resources are loaded / ready
- * @return true if ready, false otherwise
+ * @brief Called when the visuals resources are loaded / ready or failed (mean, broken image ready)
+ * @return true if ready or failed (mean, broken image ready), false otherwise
*/
virtual bool IsResourceReady() const;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
#include <dali/devel-api/common/hash.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/utility/npatch-helper.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
#include <dali-toolkit/internal/visuals/color/color-visual.h>
#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
-#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/devel-api/utility/npatch-helper.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
#include <dali/integration-api/debug.h>
namespace Dali
{
namespace Internal
{
+namespace
+{
+const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+}
VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
: mSvgRasterizeThread(NULL),
Devel::PixelBuffer pixelBuffer = LoadImageFromFile(mBrokenImageInfoContainer[brokenIndex].url);
if(pixelBuffer)
{
- pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
- mBrokenImageInfoContainer[brokenIndex].texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
+ pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+ mBrokenImageInfoContainer[brokenIndex].texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
mBrokenImageInfoContainer[brokenIndex].texture.Upload(pixelData);
- mBrokenImageInfoContainer[brokenIndex].width = pixelData.GetWidth();
+ mBrokenImageInfoContainer[brokenIndex].width = pixelData.GetWidth();
mBrokenImageInfoContainer[brokenIndex].height = pixelData.GetHeight();
}
}
geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
if(!geometry)
{
- geometry = NPatchHelper::CreateGridGeometry(Uint16Pair(3,3));
+ geometry = NPatchHelper::CreateGridGeometry(Uint16Pair(3, 3));
SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
}
}
geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
if(!geometry)
{
- geometry = NPatchHelper::CreateGridGeometry(Uint16Pair(3,3));
+ geometry = NPatchHelper::CreateGridGeometry(Uint16Pair(3, 3));
SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
}
}
TextureSet textureSet;
if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
{
- textureSet = data->GetTextures();
+ textureSet = data->GetTextures();
mBrokenImageInfoContainer[index].texture = textureSet.GetTexture(0);
NPatchHelper::ApplyTextureAndUniforms(renderer, data);
renderer.SetTextures(textureSet);
}
}
-void VisualFactoryCache::UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size)
+void VisualFactoryCache::UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size, const bool& rendererIsImage)
{
-
bool useDefaultBrokenImage = false;
if(mBrokenImageInfoContainer.size() == 0)
{
}
// Load Information for broken image
- for(uint32_t index = 0; (index < mBrokenImageInfoContainer.size()) && !useDefaultBrokenImage; index++)
+ for(uint32_t index = 0; (index < mBrokenImageInfoContainer.size()) && !useDefaultBrokenImage; index++)
{
if(mBrokenImageInfoContainer[index].width == 0 && mBrokenImageInfoContainer[index].height == 0)
{
if(mBrokenImageInfoContainer[index].visualType == VisualUrl::Type::N_PATCH)
{
const NPatchData* data;
- Rect<int> border;
- mBrokenImageInfoContainer[index].npatchId = mNPatchLoader.Load( mTextureManager, NULL, mBrokenImageInfoContainer[index].url, border, mPreMultiplyOnLoad, true);
+ Rect<int> border;
+ mBrokenImageInfoContainer[index].npatchId = mNPatchLoader.Load(mTextureManager, NULL, mBrokenImageInfoContainer[index].url, border, mPreMultiplyOnLoad, true);
if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
{
- mBrokenImageInfoContainer[index].width = data->GetCroppedWidth();
+ mBrokenImageInfoContainer[index].width = data->GetCroppedWidth();
mBrokenImageInfoContainer[index].height = data->GetCroppedHeight();
}
else
{
- DALI_LOG_ERROR("Can't update renderer for broken image. maybe image loading is failed [index:%d] [path:%s] \n",index, mBrokenImageInfoContainer[index].url.c_str());
+ DALI_LOG_ERROR("Can't update renderer for broken image. maybe image loading is failed [index:%d] [path:%s] \n", index, mBrokenImageInfoContainer[index].url.c_str());
useDefaultBrokenImage = true;
}
}
{
if(!GetBrokenVisualImage(index))
{
- DALI_LOG_ERROR("Can't update renderer for broken image. maybe image loading is failed [index:%d] [path:%s] \n",index, mBrokenImageInfoContainer[index].url.c_str());
+ DALI_LOG_ERROR("Can't update renderer for broken image. maybe image loading is failed [index:%d] [path:%s] \n", index, mBrokenImageInfoContainer[index].url.c_str());
useDefaultBrokenImage = true;
}
}
mBrokenImageInfoContainer[defaultBrokenIndex].url = mDefaultBrokenImageUrl;
VisualUrl visualUrl(mBrokenImageInfoContainer[defaultBrokenIndex].url);
mBrokenImageInfoContainer[defaultBrokenIndex].visualType = visualUrl.GetType();
- mUseDefaultBrokenImageOnly = true;
+ mUseDefaultBrokenImageOnly = true;
}
// Set Texutre to renderer
{
// Set geometry and shader for npatch
Geometry geometry = GetNPatchGeometry(brokenIndex);
- Shader shader = GetNPatchShader(brokenIndex);
+ Shader shader = GetNPatchShader(brokenIndex);
renderer.SetGeometry(geometry);
renderer.SetShader(shader);
ApplyTextureAndUniforms(renderer, brokenIndex);
}
else
{
- Texture brokenImage = GetBrokenVisualImage(brokenIndex);
- TextureSet textureSet = TextureSet::New();
+ // Create single image renderer only if rederer is not use normal ImageShader. i.e. npatch visual.
+ if(!rendererIsImage)
+ {
+ Geometry geometry = GetGeometry(QUAD_GEOMETRY);
+ Shader shader = GetShader(IMAGE_SHADER);
+ if(!shader)
+ {
+ std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data());
+ std::string fragmentShader = std::string(Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_FRAG.data());
+ shader = Shader::New(vertexShader, fragmentShader);
+ shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+ SaveShader(IMAGE_SHADER, shader);
+ }
+ renderer.SetGeometry(geometry);
+ renderer.SetShader(shader);
+ }
+ Texture brokenImage = GetBrokenVisualImage(brokenIndex);
+ TextureSet textureSet = TextureSet::New();
textureSet.SetTexture(0u, brokenImage);
renderer.SetTextures(textureSet);
}
{
// Sets the default broken type
int32_t returnIndex = 0;
- if((size.width == 0 || size.height == 0) || mUseDefaultBrokenImageOnly )
+ if((size.width == 0 || size.height == 0) || mUseDefaultBrokenImageOnly)
{
// To do : Need to add observer about size
return returnIndex;
* @brief Update the broken image Renderer object
* @param[in,out] renderer renderer for broken image
* @param[in] size the size of actor
+ * @param[in] rendererIsImage True if input renderer use image shader already.
+ * If true, we don't need to create new renderer when broken image is single image.
+ * Most of user experience use normal images. So It can reduce runtime.
*/
- void UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size);
+ void UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size, const bool& rendererIsImage = true);
public:
/**
#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/gl-view/drawable-view-impl.h>
#include <dali-toolkit/internal/controls/gl-view/gl-view-impl.h>
-namespace Dali
+namespace Dali::Toolkit
{
-namespace Toolkit
-{
-GlView::GlView()
-{
-}
+
+GlView::GlView() = default;
GlView::GlView(const GlView& GlView) = default;
GlView& GlView::operator=(GlView&& rhs) = default;
-GlView::~GlView()
+GlView::~GlView() = default;
+
+GlView GlView::New(ColorFormat colorFormat)
{
+ // This function is backward compatible and always returns
+ // backend based on NativeImage.
+ return Internal::GlView::New( colorFormat );
}
-GlView GlView::New(ColorFormat colorFormat)
+GlView GlView::New(BackendMode backendMode, ColorFormat colorFormat)
{
- return Internal::GlView::New(colorFormat);
+ switch(backendMode)
+ {
+ case BackendMode::DIRECT_RENDERING:
+ {
+ return Internal::DrawableView::New();
+ }
+ case BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING:
+ {
+ return Internal::GlView::New(colorFormat);
+ }
+ default:
+ {
+ DALI_ASSERT_ALWAYS("Invalid BackendMode");
+ }
+ }
+ return {};
}
GlView GlView::DownCast(BaseHandle handle)
{
- return Control::DownCast<GlView, Internal::GlView>(handle);
+ return Control::DownCast<GlView, Internal::GlViewImpl>(handle);
}
void GlView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
return Dali::Toolkit::GetImpl(*this).GetRenderingMode();
}
+Dali::Toolkit::GlView::BackendMode GlView::GetBackendMode() const
+{
+ return Dali::Toolkit::GetImpl(*this).GetBackendMode();
+}
+
void GlView::RenderOnce()
{
Dali::Toolkit::GetImpl(*this).RenderOnce();
}
-GlView::GlView(Internal::GlView& implementation)
+GlView::GlView(Internal::GlViewImpl& implementation)
: Control(implementation)
{
}
GlView::GlView(Dali::Internal::CustomActor* internal)
: Control(internal)
{
- VerifyCustomActorPointer<Internal::GlView>(internal);
+ VerifyCustomActorPointer<Internal::GlViewImpl>(internal);
}
-} // namespace Toolkit
-
} // namespace Dali
{
namespace Internal DALI_INTERNAL
{
-class GlView;
+class GlViewImpl;
}
/**
* GlView creates a GL context, a GL surface and a render thread.
* The render thread invokes user's callbacks.
*
+ * @SINCE_2_0.45
*/
class DALI_TOOLKIT_API GlView : public Dali::Toolkit::Control
{
public:
+
+ /**
+ * @brief Implementation backend mode
+ *
+ * @SINCE_2_1.18
+ */
+ enum class BackendMode
+ {
+ /**
+ * DIRECT_RENDERING mode executes GL code within DALi graphics
+ * pipeline. When Renderer is about to be drawn, the callback
+ * will be executed and the custom code "injected" into the pipeline.
+ * This allows rendering directly to the surface rather than offscreen.
+ */
+ DIRECT_RENDERING = 0,
+
+ /**
+ * EGL_IMAGE_OFFSCREEN_RENDERING mode executes GL code in own thread
+ * and renders to the offscreen NativeImage (EGL) buffer. This backend
+ * will render in parallel but has higher memory footprint and may suffer
+ * performance issues due to using EGL image.
+ */
+ EGL_IMAGE_OFFSCREEN_RENDERING,
+
+ /**
+ * The default mode is set to EGL_IMAGE_OFFSCREEN_RENDERING for backwards
+ * compatibility.
+ */
+ DEFAULT = EGL_IMAGE_OFFSCREEN_RENDERING
+ };
+
/**
* @brief Enumeration for rendering mode
*
* It has two options.
* One of them is continuous mode. It is rendered continuously.
* The other is on demand mode. It is rendered by application.
+ *
+ * @SINCE_2_0.45
*/
enum class RenderingMode
{
* @brief Enumeration for Graphics API version
*
* This Enumeration is used to set a GLES version for EGL configuration.
+ *
+ * @SINCE_2_0.45
*/
enum class GraphicsApiVersion
{
* @brief Enumeration for color buffer format
*
* This Enumeration is used to set a color buffer format of GlView
+ *
+ * @SINCE_2_0.45
*/
enum class ColorFormat
{
/**
* @brief Creates a GlView control.
+ *
+ * @note This function always creates the GlView with NativeImage backend.
+ *
* @param[in] colorFormat the format of the color buffer.
* @return A handle to a GlView control
+ *
+ * @SINCE_2_0.45
*/
static GlView New(ColorFormat colorFormat);
/**
+ * @brief Creates a GlView control.
+ *
+ * The new GlView will be created with specified backend.
+ * The colorFormat is ignored for DIRECT_RENDERING backend.
+ *
+ * @param[in] colorFormat the format of the color buffer.
+ * @param[in] backendMode the backend used by the GlView
+ * @return A handle to a GlView control
+ *
+ * @SINCE_2_1.18
+ */
+ static GlView New(BackendMode backendMode, ColorFormat colorFormat);
+
+ /**
* @brief Creates an uninitialized GlView.
+ *
+ * @SINCE_2_0.45
*/
GlView();
* @brief Destructor.
*
* This is non-virtual since derived Handle types must not contain data or virtual methods.
+ *
+ * @SINCE_2_0.45
*/
~GlView();
* @brief Copy constructor.
*
* @param[in] GlView GlView to copy. The copied GlView will point at the same implementation
+ *
+ * @SINCE_2_0.45
*/
GlView(const GlView& GlView);
* @brief Move constructor
*
* @param[in] rhs A reference to the moved handle
+ *
+ * @SINCE_2_0.45
*/
GlView(GlView&& rhs);
*
* @param[in] GlView The GlView to assign from
* @return A reference to this
+ *
+ * @SINCE_2_0.45
*/
GlView& operator=(const GlView& GlView);
*
* @param[in] rhs A reference to the moved handle
* @return A reference to this
+ *
+ * @SINCE_2_0.45
*/
GlView& operator=(GlView&& rhs);
*
* @param[in] handle Handle to an object
* @return Handle to a GlView or an uninitialized handle
+ *
+ * @SINCE_2_0.45
*/
static GlView DownCast(BaseHandle handle);
* @note Ownership of the callbacks is passed onto this class.
* <b>You can't call Dali APIs in your callbacks because it is invoked in GlView's own render thread.</b>
* And this must be called before adding GlView to the scene.
+ *
+ * @SINCE_2_0.45
*/
void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
* @note Ownership of the callback is passed onto this class.
* <b>You can't call Dali APIs in your callback because it is invoked in GlView's own render thread.</b>
* And this must be called before adding GlView to the scene.
+ *
+ * @SINCE_2_0.45
*/
void SetResizeCallback(CallbackBase* resizeCallback);
*
* @note The default Rendering mode is CONTINUOUS.
* If ON_DEMAND mode is set, it is rendered by RenderOnce()
+ *
+ * @SINCE_2_0.45
*/
void SetRenderingMode(RenderingMode mode);
/**
* @brief Gets the rendering mode.
+ *
+ * @SINCE_2_0.45
+ */
+ [[nodiscard]] RenderingMode GetRenderingMode() const;
+
+ /**
+ * @brief Gets the backend mode.
+ *
+ * @SINCE_2_1.18
*/
- RenderingMode GetRenderingMode() const;
+ [[nodiscard]] BackendMode GetBackendMode() const;
/**
* @brief Sets egl configuration for GlView
* @param[in] msaa the expected sampling number per pixel.
* @param[in] version the graphics API version
* @return True if the config exists, false otherwise.
+ *
+ * @SINCE_2_0.45
*/
bool SetGraphicsConfig(bool depth, bool stencil, int msaa, GraphicsApiVersion version);
/**
* @brief Renders once more even if GL render functions are not added to idler.
* @note Will not work if the window is hidden or GL render functions are added to idler
+ *
+ * @SINCE_2_0.45
*/
void RenderOnce();
/**
* @brief Creates a handle using the Toolkit::Internal implementation.
* @param[in] implementation The GlView implementation
+ *
+ * @SINCE_2_0.45
*/
- DALI_INTERNAL GlView(Internal::GlView& implementation);
+ DALI_INTERNAL GlView(Internal::GlViewImpl& implementation);
/**
* @brief Allows the creation of this GlView from an Internal::CustomActor pointer.
* @param[in] internal A pointer to the internal CustomActor
+ *
+ * @SINCE_2_0.45
*/
DALI_INTERNAL GlView(Dali::Internal::CustomActor* internal);
/// @endcond
{
const unsigned int TOOLKIT_MAJOR_VERSION = 2;
const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 15;
+const unsigned int TOOLKIT_MICRO_VERSION = 18;
const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali2-toolkit
Summary: Dali 3D engine Toolkit
-Version: 2.1.15
+Version: 2.1.18
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT