${TEST_HARNESS_DIR}/test-harness.cpp
${TEST_HARNESS_DIR}/test-gesture-generator.cpp
${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
- ${TEST_HARNESS_DIR}/test-gl-sync-abstraction.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-sync-impl.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-sync-object.cpp
${TEST_HARNESS_DIR}/test-graphics-buffer.cpp
${TEST_HARNESS_DIR}/test-graphics-command-buffer.cpp
${TEST_HARNESS_DIR}/test-graphics-controller.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-framebuffer.cpp
${TEST_HARNESS_DIR}/test-graphics-texture.cpp
${TEST_HARNESS_DIR}/test-graphics-sampler.cpp
${TEST_HARNESS_DIR}/test-graphics-pipeline.cpp
utc-Dali-Gltf2Loader.cpp
utc-Dali-KtxLoader.cpp
utc-Dali-MatrixStack.cpp
+ utc-Dali-MeshDefinition.cpp
utc-Dali-NodeDefinition.cpp
utc-Dali-RendererState.cpp
utc-Dali-ResourceBundle.cpp
${TEST_HARNESS_DIR}/test-harness.cpp
${TEST_HARNESS_DIR}/test-gesture-generator.cpp
${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
- ${TEST_HARNESS_DIR}/test-gl-sync-abstraction.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-sync-impl.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-sync-object.cpp
${TEST_HARNESS_DIR}/test-graphics-buffer.cpp
${TEST_HARNESS_DIR}/test-graphics-command-buffer.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-framebuffer.cpp
${TEST_HARNESS_DIR}/test-graphics-controller.cpp
${TEST_HARNESS_DIR}/test-graphics-texture.cpp
${TEST_HARNESS_DIR}/test-graphics-sampler.cpp
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
END_TEST;
}
+
+int UtcDaliKtxLoaderCubeDataCreateTexture3(void)
+{
+ CubeData cubeData;
+ auto path = TEST_RESOURCE_DIR "/papermill_E_diffuse-64.ktx";
+ DALI_TEST_CHECK(LoadCubeMapData(path, cubeData));
+
+ TestApplication app;
+ auto texture = cubeData.CreateTexture();
+
+ DALI_TEST_CHECK(texture);
+ DALI_TEST_EQUAL(64u, texture.GetWidth());
+ DALI_TEST_EQUAL(64u, texture.GetHeight());
+
+ END_TEST;
+
+}
--- /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.
+ *
+ */
+
+#include <vector>
+
+#include "dali-scene-loader/public-api/mesh-definition.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxBothMinMaxApplied(void)
+{
+ using Container = std::vector<float>;
+
+ Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+ Container minValues = { 5.0f };
+ Container maxValues = { 10.0f };
+ Container result = {5.0f, 6.0f, 8.0f, 10.0f, 10.0f};
+
+ MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+ for( auto i = 0u; i < result.size(); ++i)
+ {
+ DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxOnlyMin(void)
+{
+ using Container = std::vector<float>;
+
+ Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+ Container minValues = { 5.0f };
+ Container maxValues = {};
+ Container result = {5.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+
+ MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+ for( auto i = 0u; i < result.size(); ++i)
+ {
+ DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxOnlyMax(void)
+{
+ using Container = std::vector<float>;
+
+ Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+ Container minValues = { };
+ Container maxValues = { 10.0f };
+ Container result = {4.0f, 6.0f, 8.0f, 10.0f, 10.0f};
+
+ MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+ for( auto i = 0u; i < result.size(); ++i)
+ {
+ DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxBothEmpty(void)
+{
+ using Container = std::vector<float>;
+
+ Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+ Container minValues;
+ Container maxValues;
+ Container result = {4.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+
+ MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+ for( auto i = 0u; i < result.size(); ++i)
+ {
+ DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
SET(PKG_NAME "dali-shader-generator")
SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+
+SET(CAPI_LIB "dali-shader-generator")
-PKG_CHECK_MODULES(${EXEC_NAME} REQUIRED
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+ dali2-core
+ dali2-adaptor
dali2-toolkit
)
-ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp)
+SET(TC_SOURCES
+ utc-Dali-ShaderGenerator.cpp
+)
+
+# List of test harness files (Won't get parsed for test cases)
+SET(TEST_HARNESS_DIR "../dali-toolkit/dali-toolkit-test-utils")
+
+SET(TEST_HARNESS_SOURCES
+ ${TEST_HARNESS_DIR}/toolkit-adaptor.cpp
+ ${TEST_HARNESS_DIR}/toolkit-application.cpp
+ ${TEST_HARNESS_DIR}/toolkit-event-thread-callback.cpp
+ ${TEST_HARNESS_DIR}/toolkit-environment-variable.cpp
+ ${TEST_HARNESS_DIR}/toolkit-input-method-context.cpp
+ ${TEST_HARNESS_DIR}/toolkit-input-method-options.cpp
+ ${TEST_HARNESS_DIR}/toolkit-lifecycle-controller.cpp
+ ${TEST_HARNESS_DIR}/toolkit-orientation.cpp
+ ${TEST_HARNESS_DIR}/toolkit-style-monitor.cpp
+ ${TEST_HARNESS_DIR}/toolkit-test-application.cpp
+ ${TEST_HARNESS_DIR}/toolkit-timer.cpp
+ ${TEST_HARNESS_DIR}/toolkit-trigger-event-factory.cpp
+ ${TEST_HARNESS_DIR}/toolkit-window.cpp
+ ${TEST_HARNESS_DIR}/toolkit-scene-holder.cpp
+ ${TEST_HARNESS_DIR}/dali-test-suite-utils.cpp
+ ${TEST_HARNESS_DIR}/dali-toolkit-test-suite-utils.cpp
+ ${TEST_HARNESS_DIR}/dummy-control.cpp
+ ${TEST_HARNESS_DIR}/mesh-builder.cpp
+ ${TEST_HARNESS_DIR}/test-actor-utils.cpp
+ ${TEST_HARNESS_DIR}/test-animation-data.cpp
+ ${TEST_HARNESS_DIR}/test-application.cpp
+ ${TEST_HARNESS_DIR}/test-button.cpp
+ ${TEST_HARNESS_DIR}/test-harness.cpp
+ ${TEST_HARNESS_DIR}/test-gesture-generator.cpp
+ ${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-sync-impl.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-sync-object.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-buffer.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-command-buffer.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-controller.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-framebuffer.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-texture.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-sampler.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-program.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-pipeline.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-shader.cpp
+ ${TEST_HARNESS_DIR}/test-graphics-reflection.cpp
+ ${TEST_HARNESS_DIR}/test-platform-abstraction.cpp
+ ${TEST_HARNESS_DIR}/test-render-controller.cpp
+ ${TEST_HARNESS_DIR}/test-trace-call-stack.cpp
+)
+
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+ SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+ ../../../
+ ${${CAPI_LIB}_INCLUDE_DIRS}
+ ../dali-toolkit/dali-toolkit-test-utils
+)
+
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED)
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.h ${EXEC_NAME}.cpp ${TC_SOURCES} ${TEST_HARNESS_SOURCES})
+
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+ ${${CAPI_LIB}_LIBRARIES}
+ -lpthread --coverage
+)
+
+ADD_CUSTOM_COMMAND(
+ COMMAND ${SCRIPT_DIR}/tcheadgen.sh ${EXEC_NAME}.h ${TC_SOURCES}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ OUTPUT ${EXEC_NAME}.h
+ COMMENT "Generating test tables"
+)
INSTALL(PROGRAMS ${EXEC_NAME}
- DESTINATION ${BIN_DIR}/${EXEC_NAME}
+ DESTINATION ${BIN_DIR}/${EXEC_NAME}
)
SET(SHADER_GENERATOR dali-shader-generator)
SET(GENERATED_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/shader/generated)
SET(SHADER_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/shader)
+# All the shader generator execution tests are below
+
ADD_CUSTOM_TARGET(test_help ALL COMMAND ${SHADER_GENERATOR} -h | grep "DALi Shader Generator" > /dev/null 2>&1 && echo "test_help Succeeded" VERBATIM)
ADD_CUSTOM_TARGET(test_no_params ALL COMMAND ${SHADER_GENERATOR} > /dev/null 2>&1 || echo "test_no_params Succeeded" VERBATIM)
ADD_CUSTOM_TARGET(test_version ALL COMMAND ${SHADER_GENERATOR} -v | wc -l | grep 1 > /dev/null 2>&1 && echo "test_version Succeeded" VERBATIM)
-#include <iostream>
+#include <test-harness.h>
+#include "tct-dali-shader-generator-core.h"
+
int main(int argc, char * const argv[])
{
- std::cout << "All tests run as part of Cmake build." << std::endl;
- return 0;
+ return TestHarness::RunTests(argc, argv, tc_array);
}
--- /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.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+
+void utc_dali_shader_generator_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_shader_generator_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+int UtcDaliShaderGenerator(void)
+{
+ tet_infoline("All tests run as part of cmake build");
+ DALI_TEST_CHECK(true);
+ END_TEST;
+}
utc-Dali-Text-ViewModel.cpp
utc-Dali-TextField-internal.cpp
utc-Dali-TextEditor-internal.cpp
+ utc-Dali-TextLabel-internal.cpp
utc-Dali-TextSelectionPopup-internal.cpp
utc-Dali-TextureManager.cpp
utc-Dali-Visuals-internal.cpp
utc-Dali-VisualModel.cpp
utc-Dali-VisualUrl.cpp
+ utc-Dali-Text-Hyphen-Wrapping.cpp
)
IF(ELDBUS_AVAILABLE)
../dali-toolkit/dali-toolkit-test-utils/test-button.cpp
../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
- ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-program.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-pipeline.cpp
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * 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.
#include <dali-toolkit/internal/text/shaper.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
namespace Dali
{
Size& layoutSize,
ModelPtr& textModel,
MetricsPtr& metrics,
- bool markupProcessorEnabled )
+ bool markupProcessorEnabled,
+ LineWrap::Mode wrapMode )
{
textModel = Model::New(); ///< Pointer to the text's model.
LogicalModelPtr logicalModel = textModel->mLogicalModel;
MarkupProcessData markupProcessData( logicalModel->mColorRuns,
logicalModel->mFontDescriptionRuns,
logicalModel->mEmbeddedItems,
- logicalModel->mAnchors );
+ logicalModel->mAnchors,
+ logicalModel->mUnderlinedCharacterRuns);
Length textSize = 0u;
const uint8_t* utf8 = NULL;
return;
}
+ textModel->mLineWrapMode = wrapMode;
+
+ if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+ {
+ CharacterIndex end = characterCount;
+ LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+ for(CharacterIndex index = 0; index < end; index++)
+ {
+ CharacterIndex wordEnd = index;
+ while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+ {
+ wordEnd++;
+ }
+
+ if((wordEnd + 1) == end) // add last char
+ {
+ wordEnd++;
+ }
+
+ Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+ for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+ {
+ if(hyphens[i])
+ {
+ *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+ }
+ }
+
+ index = wordEnd;
+ }
+ }
+
// 3) Set the script info.
MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
// Set the layout parameters.
textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
- textModel->mLineWrapMode = LineWrap::WORD;
textModel->mIgnoreSpacesAfterText = true;
textModel->mMatchSystemLanguageDirection = false;
Layout::Parameters layoutParameters( textArea,
#define DALI_TOOLKIT_TEXT_UTILS_H
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * 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.
Size& layoutSize,
ModelPtr& textModel,
MetricsPtr& metrics,
- bool markupProcessorEnabled );
+ bool markupProcessorEnabled,
+ LineWrap::Mode wrapMode );
/**
* @brief Configures the text @p controller similarly to the one configured by the text-label.
auto control = Control::New();
auto reading_info_type = DevelControl::GetAccessibilityReadingInfoType(control);
+
+ for ( auto i = 0u; i < 4; ++i)
+ DALI_TEST_CHECK ( reading_info_type[ static_cast< Dali::Accessibility::ReadingInfoType >( i ) ]);
+
+ reading_info_type[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = false;
+ reading_info_type[Dali::Accessibility::ReadingInfoType::STATE] = false;
+ reading_info_type[Dali::Accessibility::ReadingInfoType::NAME] = false;
+ reading_info_type[Dali::Accessibility::ReadingInfoType::ROLE] = false;
+
+ DevelControl::SetAccessibilityReadingInfoType(control, reading_info_type);
+
+ reading_info_type = DevelControl::GetAccessibilityReadingInfoType(control);
+
+ for ( auto i = 0u; i < 4; ++i)
+ DALI_TEST_CHECK ( false == reading_info_type[ static_cast< Dali::Accessibility::ReadingInfoType >( i ) ]);
+
reading_info_type[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
reading_info_type[Dali::Accessibility::ReadingInfoType::STATE] = true;
reading_info_type[Dali::Accessibility::ReadingInfoType::NAME] = true;
DALI_TEST_EQUALS( text->SetSelection( 1, 0, 1 ), false, TEST_LOCATION );
DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION );
+ DALI_TEST_EQUALS(editabletext->SetTextContents("adef"), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(editabletext->InsertText(1, "bc"), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(text->GetText(0, 6), "abcdef", TEST_LOCATION);
+ DALI_TEST_EQUALS(editabletext->DeleteText(5, 1), false, TEST_LOCATION);
+ DALI_TEST_EQUALS(editabletext->DeleteText(1, 5), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(text->GetText(0, 2), "af", TEST_LOCATION);
+
Dali::Accessibility::TestEnableSC( false );
END_TEST;
DALI_TEST_EQUALS( text->SetSelection( 1, 0, 1 ), false, TEST_LOCATION );
DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION );
+ DALI_TEST_EQUALS(editabletext->SetTextContents("adef"), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(editabletext->InsertText(1, "bc"), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(text->GetText(0, 6), "abcdef", TEST_LOCATION);
+ DALI_TEST_EQUALS(editabletext->DeleteText(5, 1), false, TEST_LOCATION);
+ DALI_TEST_EQUALS(editabletext->DeleteText(1, 5), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(text->GetText(0, 2), "af", TEST_LOCATION);
+
Dali::Accessibility::TestEnableSC( false );
END_TEST;
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- data.markupProcessorEnabled );
+ data.markupProcessorEnabled,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
--- /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.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+
+namespace
+{
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+struct LayoutTextData
+{
+ std::string text;
+ Size textArea;
+ unsigned int numberOfFonts;
+ FontDescriptionRun *fontDescriptions;
+ unsigned int numberOfLines;
+ LineRun* lines;
+ Layout::Engine::Type layout;
+ unsigned int startIndex;
+ unsigned int numberOfGlyphs;
+ Text::LineWrap::Mode wrapMode;
+};
+
+void Print( const LineRun& line )
+{
+ std::cout << " glyph run, index : " << line.glyphRun.glyphIndex << ", num glyphs : " << line.glyphRun.numberOfGlyphs << std::endl;
+ std::cout << " character run, index : " << line.characterRun.characterIndex << ", num chars : " << line.characterRun.numberOfCharacters << std::endl;
+}
+
+bool LayoutTextTest( const LayoutTextData& data )
+{
+ // Load some fonts.
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.SetDpi( 96u, 96u );
+
+ char* pathNamePtr = get_current_dir_name();
+ const std::string pathName( pathNamePtr );
+ free( pathNamePtr );
+
+ fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+
+ // 1) Create the model.
+ ModelPtr textModel;
+ MetricsPtr metrics;
+ Size layoutSize;
+
+ Vector<FontDescriptionRun> fontDescriptionRuns;
+ if( 0u != data.numberOfFonts )
+ {
+ fontDescriptionRuns.Insert( fontDescriptionRuns.End(),
+ data.fontDescriptions,
+ data.fontDescriptions + data.numberOfFonts );
+ }
+
+ LayoutOptions options;
+ options.align = false;
+ CreateTextModel( data.text,
+ data.textArea,
+ fontDescriptionRuns,
+ options,
+ layoutSize,
+ textModel,
+ metrics,
+ false,
+ data.wrapMode );
+
+ Vector<LineRun>& lines = textModel->mVisualModel->mLines;
+
+ // 4) Compare the results.
+
+ if( lines.Count() != data.numberOfLines )
+ {
+ std::cout << " Different number of lines : " << lines.Count() << ", expected : " << data.numberOfLines << std::endl;
+ return false;
+ }
+
+ for( unsigned int index = 0u; index < data.numberOfLines; ++index )
+ {
+ const LineRun& line = *( lines.Begin() + index );
+ const LineRun& expectedLine = *( data.lines + index );
+
+ if( line.characterRun.characterIndex != expectedLine.characterRun.characterIndex )
+ {
+ std::cout << " Different line info for line : " << index << std::endl;
+ Print( line );
+ std::cout << " expected" << std::endl;
+ Print( expectedLine );
+ return false;
+ }
+ if( line.characterRun.numberOfCharacters != expectedLine.characterRun.numberOfCharacters )
+ {
+ std::cout << " Different line info for line : " << index << std::endl;
+ Print( line );
+ std::cout << " expected" << std::endl;
+ Print( expectedLine );
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+
+int UtcDaliTextHyphenWrapping(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextHyphenWrapping");
+
+ // Layout some lines of left to right text.
+
+ const std::string fontFamily( "TizenSans" );
+
+ // Set a known font description
+ FontDescriptionRun fontDescriptionRun1;
+ fontDescriptionRun1.characterRun.characterIndex = 0u;
+ fontDescriptionRun1.characterRun.numberOfCharacters = 13u;
+ fontDescriptionRun1.familyLength = fontFamily.size();
+ fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+ memcpy( fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength );
+ fontDescriptionRun1.familyDefined = true;
+ fontDescriptionRun1.weightDefined = false;
+ fontDescriptionRun1.widthDefined = false;
+ fontDescriptionRun1.slantDefined = false;
+ fontDescriptionRun1.sizeDefined = false;
+
+ Vector<FontDescriptionRun> fontDescriptionRuns;
+ fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+ Size textArea(65.0f, 200.f);
+
+ LineRun line1 =
+ {
+ { 0u, 5u },
+ { 0u, 5u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+ LineRun line2 =
+ {
+ { 5u, 8u },
+ { 5u, 8u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+
+ Vector<LineRun> lines;
+ lines.PushBack( line1 );
+ lines.PushBack( line2 );
+
+ LayoutTextData data =
+ {
+ "Hi Experiment",
+ textArea,
+ 1u,
+ fontDescriptionRuns.Begin(),
+ 2u,
+ lines.Begin(),
+ Layout::Engine::MULTI_LINE_BOX,
+ 0u,
+ 13u,
+ (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION
+ };
+
+ if( !LayoutTextTest( data ) )
+ {
+ tet_result(TET_FAIL);
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
+
+int UtcDaliTextMixedWrapping(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextMixedWrapping");
+
+ // Layout some lines of left to right text.
+
+ const std::string fontFamily( "DejaVuSans" );
+
+ // Set a known font description
+ FontDescriptionRun fontDescriptionRun1;
+ fontDescriptionRun1.characterRun.characterIndex = 0u;
+ fontDescriptionRun1.characterRun.numberOfCharacters = 13u;
+ fontDescriptionRun1.familyLength = fontFamily.size();
+ fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+ memcpy( fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength );
+ fontDescriptionRun1.familyDefined = true;
+ fontDescriptionRun1.weightDefined = false;
+ fontDescriptionRun1.widthDefined = false;
+ fontDescriptionRun1.slantDefined = false;
+ fontDescriptionRun1.sizeDefined = false;
+
+ Vector<FontDescriptionRun> fontDescriptionRuns;
+ fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+ Size textArea(72.0f, 200.f);
+
+ LineRun line1 =
+ {
+ { 0u, 3u },
+ { 0u, 3u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+ LineRun line2 =
+ {
+ { 3u, 6u },
+ { 3u, 6u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+ LineRun line3 =
+ {
+ { 9u, 4u },
+ { 9u, 4u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+
+ Vector<LineRun> lines;
+ lines.PushBack( line1 );
+ lines.PushBack( line2 );
+ lines.PushBack( line3 );
+
+ LayoutTextData data =
+ {
+ "Hi Experiment",
+ textArea,
+ 1u,
+ fontDescriptionRuns.Begin(),
+ 3u,
+ lines.Begin(),
+ Layout::Engine::MULTI_LINE_BOX,
+ 0u,
+ 13u,
+ (Text::LineWrap::Mode)DevelText::LineWrap::MIXED
+ };
+
+ if( !LayoutTextTest( data ) )
+ {
+ tet_result(TET_FAIL);
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
\ No newline at end of file
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
Vector<FontDescriptionRun> fontRuns;
Vector<EmbeddedItem> items;
Vector<Anchor> anchors;
- MarkupProcessData markupProcessData( colorRuns, fontRuns, items, anchors );
+ Vector<UnderlinedCharacterRun> underlinedCharacterRuns;
+ MarkupProcessData markupProcessData( colorRuns, fontRuns, items, anchors, underlinedCharacterRuns );
ProcessMarkupString( data.xHTMLEntityString, markupProcessData );
for( Vector<EmbeddedItem>::Iterator it = items.Begin(),
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
#include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
#include <dali-toolkit/internal/text/text-controller.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
END_TEST;
}
+
+int UtcDaliTextEditorMarkupUnderline(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextEditorMarkupUnderline ");
+
+ TextEditor textEditor = TextEditor::New();
+
+ application.GetScene().Add( textEditor );
+
+ textEditor.SetProperty( TextEditor::Property::TEXT, "<u>ABC</u>EF<u>GH</u>" );
+ textEditor.SetProperty( TextEditor ::Property::ENABLE_MARKUP, true );
+
+ application.SendNotification();
+ application.Render();
+
+ uint32_t expectedNumberOfUnderlinedGlyphs = 5u;
+
+ Toolkit::Internal::TextEditor& textEditorImpl = GetImpl( textEditor );
+ const Text::Length numberOfUnderlineRuns = textEditorImpl.getController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+ DALI_TEST_EQUALS( numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION );
+
+ Vector<GlyphRun> underlineRuns;
+ underlineRuns.Resize(numberOfUnderlineRuns);
+ textEditorImpl.getController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+ //ABC are underlined
+ DALI_TEST_EQUALS( underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+
+ //GH are underlined
+ DALI_TEST_EQUALS( underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliTextEditorFontPointSizeLargerThanAtlas(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextEditorFontPointSizeLargerThanAtlas ");
+
+ // Create a text editor
+ TextEditor textEditor = TextEditor::New();
+ //Set size to avoid automatic eliding
+ textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ //Set very large font-size using point-size
+ textEditor.SetProperty( TextEditor::Property::POINT_SIZE, 1000);
+ //Specify font-family
+ textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+ //Set text to check if appear or not
+ textEditor.SetProperty(TextEditor::Property::TEXT, "A");
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+
+ //Check if Glyph is added to AtlasGlyphManger or not
+ int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+ DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliTextEditorFontPointSizeLargerThanAtlasPlaceholderCase(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextEditorFontPointSizeLargerThanAtlasPlaceholderCase ");
+
+ //Set Map of placeholder: text, font-family and point-size
+ Property::Map placeholderMapSet;
+ placeholderMapSet["text"] = "A";
+ placeholderMapSet["fontFamily"] = "DejaVu Sans";
+ placeholderMapSet["pixelSize"] = 1000.0f;
+
+ // Create a text editor
+ TextEditor textEditor = TextEditor::New();
+ //Set size to avoid automatic eliding
+ textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ //Set placeholder
+ textEditor.SetProperty( TextEditor::Property::PLACEHOLDER, placeholderMapSet) ;
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+
+ //Check if Glyph is added to AtlasGlyphManger or not
+ int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+ DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+ END_TEST;
+}
\ No newline at end of file
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
#include <dali-toolkit/internal/text/text-controller.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
END_TEST;
}
+
+int UtcDaliTextFieldMarkupUnderline(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextFieldMarkupUnderline ");
+
+ TextField textField = TextField::New();
+
+ application.GetScene().Add( textField );
+
+ textField.SetProperty( TextField::Property::TEXT, "<u>ABC</u>EF<u>GH</u>" );
+ textField.SetProperty( TextField ::Property::ENABLE_MARKUP, true );
+
+ application.SendNotification();
+ application.Render();
+
+ uint32_t expectedNumberOfUnderlinedGlyphs = 5u;
+
+ Toolkit::Internal::TextField& textFieldImpl = GetImpl( textField );
+ const Text::Length numberOfUnderlineRuns = textFieldImpl.getController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+ DALI_TEST_EQUALS( numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION );
+
+ Vector<GlyphRun> underlineRuns;
+ underlineRuns.Resize(numberOfUnderlineRuns);
+ textFieldImpl.getController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+ //ABC are underlined
+ DALI_TEST_EQUALS( underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+
+ //GH are underlined
+ DALI_TEST_EQUALS( underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+
+ END_TEST;
+
+}
+
+int UtcDaliTextFieldFontPointSizeLargerThanAtlas(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextFieldFontPointSizeLargerThanAtlas ");
+
+ // Create a Text field
+ TextField textField = TextField::New();
+ //Set size to avoid automatic eliding
+ textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ //Set very large font-size using point-size
+ textField.SetProperty( TextField::Property::POINT_SIZE, 1000) ;
+ //Specify font-family
+ textField.SetProperty( TextField::Property::FONT_FAMILY, "DejaVu Sans");
+ //Set text to check if appear or not
+ textField.SetProperty( TextField::Property::TEXT, "A");
+
+ application.GetScene().Add( textField );
+
+ application.SendNotification();
+ application.Render();
+
+ //Check if Glyph is added to AtlasGlyphManger or not
+ int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+ DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+
+ END_TEST;
+}
+
+int UtcDaliTextFieldFontPointSizeLargerThanAtlasPlaceholderCase(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextFieldFontPointSizeLargerThanAtlasPlaceholderCase ");
+
+ //Set Map of placeholder: text, font-family and point-size
+ Property::Map placeholderMapSet;
+ placeholderMapSet["text"] = "A";
+ placeholderMapSet["fontFamily"] = "DejaVu Sans";
+ placeholderMapSet["pixelSize"] = 1000.0f;
+
+ // Create a text editor
+ TextField textField = TextField::New();
+ //Set size to avoid automatic eliding
+ textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ //Set placeholder
+ textField.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet) ;
+
+ application.GetScene().Add( textField );
+
+ application.SendNotification();
+ application.Render();
+
+ //Check if Glyph is added to AtlasGlyphManger or not
+ int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+ DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+
+ END_TEST;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+#include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+int UtcDaliTextLabelMarkupUnderline(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextLabelMarkupUnderline ");
+
+ TextLabel textLabel = TextLabel::New();
+
+ application.GetScene().Add( textLabel );
+
+ textLabel.SetProperty( TextLabel::Property::TEXT, "<u>ABC</u>EF<u>GH</u>" );
+ textLabel.SetProperty( TextLabel ::Property::ENABLE_MARKUP, true );
+
+ application.SendNotification();
+ application.Render();
+
+ uint32_t expectedNumberOfUnderlinedGlyphs = 5u;
+
+ Toolkit::Internal::TextLabel& textLabelImpl = GetImpl( textLabel );
+ const Text::Length numberOfUnderlineRuns = textLabelImpl.getController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+ DALI_TEST_EQUALS( numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION );
+
+ Vector<GlyphRun> underlineRuns;
+ underlineRuns.Resize(numberOfUnderlineRuns);
+ textLabelImpl.getController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+ //ABC are underlined
+ DALI_TEST_EQUALS( underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+
+ //GH are underlined
+ DALI_TEST_EQUALS( underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
+ DALI_TEST_EQUALS( underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+
+ END_TEST;
+
+}
\ No newline at end of file
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
../dali-toolkit/dali-toolkit-test-utils/test-application.cpp
../dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.cpp
../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
- ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-pipeline.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-program.cpp
../dali-toolkit/dali-toolkit-test-utils/test-button.cpp
../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
- ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-sampler.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-pipeline.cpp
dali-toolkit-test-utils/test-harness.cpp
dali-toolkit-test-utils/test-gesture-generator.cpp
dali-toolkit-test-utils/test-gl-abstraction.cpp
- dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+ dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+ dali-toolkit-test-utils/test-graphics-sync-object.cpp
dali-toolkit-test-utils/test-graphics-buffer.cpp
dali-toolkit-test-utils/test-graphics-command-buffer.cpp
dali-toolkit-test-utils/test-graphics-controller.cpp
+ dali-toolkit-test-utils/test-graphics-framebuffer.cpp
dali-toolkit-test-utils/test-graphics-texture.cpp
dali-toolkit-test-utils/test-graphics-pipeline.cpp
dali-toolkit-test-utils/test-graphics-program.cpp
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
return actor;
}
+Actor CreateRenderableActor2(TextureSet textures, const std::string& vertexShader, const std::string& fragmentShader)
+{
+ // Create the geometry
+ Geometry geometry = CreateQuadGeometry();
+
+ // Create Shader
+ Shader shader = Shader::New(vertexShader, fragmentShader);
+
+ // Create renderer from geometry and material
+ Renderer renderer = Renderer::New(geometry, shader);
+
+ // Create actor and set renderer
+ Actor actor = Actor::New();
+ actor.AddRenderer(renderer);
+
+ // If we a texture, then create a texture-set and add to renderer
+ if(textures)
+ {
+ renderer.SetTextures(textures);
+
+ auto texture = textures.GetTexture(0);
+
+ // Set actor to the size of the texture if set
+ actor.SetProperty(Actor::Property::SIZE, Vector2(texture.GetWidth(), texture.GetHeight()));
+ }
+
+ return actor;
+}
+
+Texture CreateTexture(TextureType::Type type, Pixel::Format format, int width, int height)
+{
+ Texture texture = Texture::New(type, format, width, height);
+
+ int bufferSize = width * height * 2;
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+ PixelData pixelData = PixelData::New(buffer, bufferSize, width, height, format, PixelData::FREE);
+ texture.Upload(pixelData, 0u, 0u, 0u, 0u, width, height);
+ return texture;
+}
+
} // namespace Dali
#define DALI_TEST_ACTOR_UTILS_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
*/
// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/texture.h>
#include <string>
namespace Dali
*/
Actor CreateRenderableActor(Texture texture, const std::string& vertexShader, const std::string& fragmentShader);
+/**
+ * @brief Creates a renderable-actor with a texture and custom shaders.
+ * @param[in] textures TextureSet to set.
+ * @param[in] vertexShader The vertex-shader.
+ * @param[in] fragmentShader The fragment-shader.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor2(TextureSet textures, const std::string& vertexShader, const std::string& fragmentShader);
+
+Texture CreateTexture(TextureType::Type type, Pixel::Format format, int width, int height);
+
} // namespace Dali
#endif // DALI_TEST_ACTOR_UTILS_H
{
mScene = Dali::Integration::Scene::New(Size(static_cast<float>(mSurfaceWidth), static_cast<float>(mSurfaceHeight)));
mScene.SetDpi(Vector2(static_cast<float>(mDpi.x), static_cast<float>(mDpi.y)));
+
+ // Create render target for the scene
+ Graphics::RenderTargetCreateInfo rtInfo{};
+ rtInfo.SetExtent({mSurfaceWidth, mSurfaceHeight});
+ mRenderTarget = mGraphicsController.CreateRenderTarget(rtInfo, nullptr);
+ mScene.SetSurfaceRenderTarget(mRenderTarget.get());
}
void TestApplication::InitializeCore()
return static_cast<TestGlAbstraction&>(mGraphicsController.GetGlAbstraction());
}
-TestGlSyncAbstraction& TestApplication::GetGlSyncAbstraction()
+TestGlContextHelperAbstraction& TestApplication::GetGlContextHelperAbstraction()
{
- return static_cast<TestGlSyncAbstraction&>(mGraphicsController.GetGlSyncAbstraction());
+ return static_cast<TestGlContextHelperAbstraction&>(mGraphicsController.GetGlContextHelperAbstraction());
}
-TestGlContextHelperAbstraction& TestApplication::GetGlContextHelperAbstraction()
+TestGraphicsSyncImplementation& TestApplication::GetGraphicsSyncImpl()
{
- return static_cast<TestGlContextHelperAbstraction&>(mGraphicsController.GetGlContextHelperAbstraction());
+ return static_cast<TestGraphicsSyncImplementation&>(mGraphicsController.GetGraphicsSyncImpl());
}
void TestApplication::ProcessEvent(const Integration::Event& event)
TestGraphicsController& GetGraphicsController();
TestGlAbstraction& GetGlAbstraction();
- TestGlSyncAbstraction& GetGlSyncAbstraction();
TestGlContextHelperAbstraction& GetGlContextHelperAbstraction();
+ TestGraphicsSyncImplementation& GetGraphicsSyncImpl();
void ProcessEvent(const Integration::Event& event);
void SendNotification();
uint32_t mSurfaceHeight;
uint32_t mFrame;
+ Graphics::UniquePtr<Graphics::RenderTarget> mRenderTarget;
+
struct
{
uint32_t x;
#include "test-gl-abstraction.h"
#include "test-trace-call-stack.h"
+static const bool TRACE{
+ false};
+
namespace Dali
{
TestGlAbstraction::TestGlAbstraction()
-: mBufferTrace(true, std::string("gl")),
- mCullFaceTrace(true, "gl"),
- mEnableDisableTrace(true, "gl"),
- mShaderTrace(true, "gl"),
- mTextureTrace(true, std::string("gl")),
- mTexParameterTrace(true, "gl"),
- mDrawTrace(true, "gl"),
- mDepthFunctionTrace(true, "gl"),
- mStencilFunctionTrace(true, "gl"),
- mScissorTrace(true, "gl"),
- mSetUniformTrace(true, "Uniform "),
- mViewportTrace(true, "gl")
+: mBufferTrace(TRACE, std::string("gl")),
+ mCullFaceTrace(TRACE, "gl"),
+ mEnableDisableTrace(TRACE, "gl"),
+ mShaderTrace(TRACE, "gl"),
+ mTextureTrace(TRACE, std::string("gl")),
+ mTexParameterTrace(TRACE, "gl"),
+ mDrawTrace(TRACE, "gl"),
+ mDepthFunctionTrace(TRACE, "gl"),
+ mStencilFunctionTrace(TRACE, "gl"),
+ mScissorTrace(TRACE, "gl"),
+ mSetUniformTrace(TRACE, "Uniform "),
+ mViewportTrace(TRACE, "gl")
{
Initialize();
}
mCurrentProgram = 0;
mCompileStatus = GL_TRUE;
mLinkStatus = GL_TRUE;
- mNumberOfActiveUniforms = 0;
mGetErrorResult = 0;
mGetStringResult = NULL;
mIsBufferResult = 0;
{
mVertexAttribArrayState[i] = false;
}
+
+ mActiveUniforms = std::vector<ActiveUniform>{
+ {"uRendererColor", GL_FLOAT, 1},
+ {"uCustom", GL_FLOAT_VEC3, 1},
+ {"uCustom3", GL_FLOAT_VEC3, 1},
+ {"uFadeColor", GL_FLOAT_VEC4, 1},
+ {"uUniform1", GL_FLOAT_VEC4, 1},
+ {"uUniform2", GL_FLOAT_VEC4, 1},
+ {"uUniform3", GL_FLOAT_VEC4, 1},
+ {"uFadeProgress", GL_FLOAT, 1},
+ {"uANormalMatrix", GL_FLOAT_MAT3, 1},
+ {"sEffect", GL_SAMPLER_2D, 1},
+ {"sTexture", GL_SAMPLER_2D, 1},
+ {"sTextureRect", GL_SAMPLER_2D, 1},
+ {"sGloss", GL_SAMPLER_2D, 1},
+ {"uColor", GL_FLOAT_VEC4, 1},
+ {"uModelMatrix", GL_FLOAT_MAT4, 1},
+ {"uModelView", GL_FLOAT_MAT4, 1},
+ {"uMvpMatrix", GL_FLOAT_MAT4, 1},
+ {"uNormalMatrix", GL_FLOAT_MAT4, 1},
+ {"uProjection", GL_FLOAT_MAT4, 1},
+ {"uSize", GL_FLOAT_VEC3, 1},
+ {"uViewMatrix", GL_FLOAT_MAT4, 1},
+ {"uLightCameraProjectionMatrix", GL_FLOAT_MAT4, 1},
+ {"uLightCameraViewMatrix", GL_FLOAT_MAT4, 1}};
}
void TestGlAbstraction::PreRender()
}
};
+struct ActiveUniform
+{
+ std::string name;
+ GLenum type;
+ GLint size;
+};
+
class DALI_CORE_API TestGlAbstraction : public Dali::Integration::GlAbstraction
{
public:
{
mFramebufferStencilAttached = true;
}
+ else if(attachment == GL_DEPTH_STENCIL_ATTACHMENT)
+ {
+ mFramebufferStencilAttached = true;
+ mFramebufferDepthAttached = true;
+ }
}
inline void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) override
{
}
+ inline void SetActiveUniforms(const std::vector<ActiveUniform>& uniforms)
+ {
+ mActiveUniforms = uniforms;
+ }
+
inline void GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) override
{
- switch(index)
+ if(index < mActiveUniforms.size())
{
- case 0:
- *length = snprintf(name, bufsize, "sTexture");
- *type = GL_SAMPLER_2D;
- *size = 1;
- break;
- case 1:
- *length = snprintf(name, bufsize, "sEffect");
- *type = GL_SAMPLER_2D;
- *size = 1;
- break;
- case 2:
- *length = snprintf(name, bufsize, "sGloss");
- *type = GL_SAMPLER_2D;
- *size = 1;
- break;
- default:
- break;
+ *length = snprintf(name, bufsize, "%s", mActiveUniforms[index].name.c_str());
+ *type = mActiveUniforms[index].type;
+ *size = mActiveUniforms[index].size;
}
}
*params = mProgramBinaryLength;
break;
case GL_ACTIVE_UNIFORMS:
- *params = mNumberOfActiveUniforms;
+ *params = mActiveUniforms.size();
break;
case GL_ACTIVE_UNIFORM_MAX_LENGTH:
*params = 100;
namedParams["program"] << program;
mShaderTrace.PushCall("LinkProgram", out.str(), namedParams);
- mNumberOfActiveUniforms = 3;
-
- GetUniformLocation(program, "uRendererColor");
- GetUniformLocation(program, "uCustom");
- GetUniformLocation(program, "uCustom3");
- GetUniformLocation(program, "uFadeColor");
- GetUniformLocation(program, "uUniform1");
- GetUniformLocation(program, "uUniform2");
- GetUniformLocation(program, "uUniform3");
- GetUniformLocation(program, "uFadeProgress");
- GetUniformLocation(program, "uANormalMatrix");
- GetUniformLocation(program, "sEffect");
- GetUniformLocation(program, "sTexture");
- GetUniformLocation(program, "sTextureRect");
- GetUniformLocation(program, "sGloss");
- GetUniformLocation(program, "uColor");
- GetUniformLocation(program, "uModelMatrix");
- GetUniformLocation(program, "uModelView");
- GetUniformLocation(program, "uMvpMatrix");
- GetUniformLocation(program, "uNormalMatrix");
- GetUniformLocation(program, "uProjection");
- GetUniformLocation(program, "uSize");
- GetUniformLocation(program, "uViewMatrix");
- GetUniformLocation(program, "uLightCameraProjectionMatrix");
- GetUniformLocation(program, "uLightCameraViewMatrix");
+ for(const auto& uniform : mActiveUniforms)
+ {
+ GetUniformLocation(program, uniform.name.c_str());
+ }
for(const auto& uniform : mCustomUniformData)
{
mBufferSubDataCalls.clear();
}
-private:
+public:
GLuint mCurrentProgram;
GLuint mCompileStatus;
BufferDataCalls mBufferDataCalls;
BufferSubDataCalls mBufferSubDataCalls;
GLvoid* mMappedBuffer{nullptr};
GLuint mLinkStatus;
- GLint mNumberOfActiveUniforms;
GLenum mGetErrorResult;
GLubyte* mGetStringResult;
GLboolean mIsBufferResult;
typedef std::map<std::string, GLint> UniformIDMap;
typedef std::map<GLuint, UniformIDMap> ProgramUniformMap;
ProgramUniformMap mUniforms;
-
- std::vector<UniformData> mCustomUniformData{};
+ std::vector<ActiveUniform> mActiveUniforms;
+ std::vector<UniformData> mCustomUniformData{};
template<typename T>
struct ProgramUniformValue : public std::map<GLuint, std::map<GLint, T> >
return target;
}
-void TestGraphicsBuffer::BindAsUniformBuffer(const TestGraphicsProgram* program) const
+void TestGraphicsBuffer::BindAsUniformBuffer(const TestGraphicsProgram* program, const Dali::UniformBufferBindingDescriptor& uboBinding) const
{
auto* reflection = static_cast<const TestGraphicsReflection*>(&program->GetReflection());
Graphics::UniformBlockInfo uboInfo{};
reflection->GetUniformBlock(0, uboInfo);
- auto* data = memory.data();
+ auto offset = uboBinding.offset;
+ auto* data = memory.data() + offset;
for(const auto& member : uboInfo.members)
{
namespace Dali
{
class TestGraphicsProgram;
+class UniformBufferBindingDescriptor;
class TestGraphicsBuffer : public Graphics::Buffer
{
public:
return true;
}
- void BindAsUniformBuffer(const TestGraphicsProgram* program) const;
+ void BindAsUniformBuffer(const TestGraphicsProgram* program, const Dali::UniformBufferBindingDescriptor& uboBinding) const;
TraceCallStack& mCallStack;
TestGlAbstraction& mGl;
namespace Dali
{
+std::ostream& operator<<(std::ostream& os, Graphics::StencilOp op)
+{
+ switch(op)
+ {
+ case Graphics::StencilOp::KEEP:
+ os << "KEEP";
+ return os;
+ case Graphics::StencilOp::ZERO:
+ os << "ZERO";
+ return os;
+ case Graphics::StencilOp::REPLACE:
+ os << "REPLACE";
+ return os;
+ case Graphics::StencilOp::INCREMENT_AND_CLAMP:
+ os << "INCREMENT_AND_CLAMP";
+ return os;
+ case Graphics::StencilOp::DECREMENT_AND_CLAMP:
+ os << "DECREMENT_AND_CLAMP";
+ return os;
+ case Graphics::StencilOp::INVERT:
+ os << "INVERT";
+ return os;
+ case Graphics::StencilOp::INCREMENT_AND_WRAP:
+ os << "INCREMENT_AND_WRAP";
+ return os;
+ case Graphics::StencilOp::DECREMENT_AND_WRAP:
+ os << "DECREMENT_AND_WRAP";
+ return os;
+ }
+ return os;
+};
+
+std::ostream& operator<<(std::ostream& os, Graphics::CompareOp op)
+{
+ switch(op)
+ {
+ case Graphics::CompareOp::NEVER:
+ os << "NEVER";
+ return os;
+ case Graphics::CompareOp::LESS:
+ os << "LESS";
+ return os;
+ case Graphics::CompareOp::EQUAL:
+ os << "EQUAL";
+ return os;
+ case Graphics::CompareOp::LESS_OR_EQUAL:
+ os << "LESS_OR_EQUAL";
+ return os;
+ case Graphics::CompareOp::GREATER:
+ os << "GREATER";
+ return os;
+ case Graphics::CompareOp::NOT_EQUAL:
+ os << "NOT_EQUAL";
+ return os;
+ case Graphics::CompareOp::GREATER_OR_EQUAL:
+ os << "GREATER_OR_EQUAL";
+ return os;
+ case Graphics::CompareOp::ALWAYS:
+ os << "ALWAYS";
+ return os;
+ }
+ return os;
+};
+
TestGraphicsCommandBuffer::TestGraphicsCommandBuffer(TraceCallStack& callstack, TestGlAbstraction& glAbstraction)
: mCallStack(callstack),
mGlAbstraction(glAbstraction)
}
}
-std::vector<Command*> TestGraphicsCommandBuffer::GetCommandsByType(CommandTypeMask mask)
+std::vector<const Command*> TestGraphicsCommandBuffer::GetCommandsByType(CommandTypeMask mask) const
{
- std::vector<Command*> mCommandStack{};
+ std::vector<const Command*> mCommandStack{};
for(auto& cmd : mCommands)
{
if(uint32_t(cmd.type) == (mask & uint32_t(cmd.type)))
return mCommandStack;
}
+std::vector<const Command*> TestGraphicsCommandBuffer::GetChildCommandsByType(CommandTypeMask mask) const
+{
+ std::vector<const Command*> mCommandStack{};
+ for(auto& cmd : mCommands)
+ {
+ if(uint32_t(cmd.type) == (mask & uint32_t(cmd.type)))
+ {
+ mCommandStack.emplace_back(&cmd);
+ }
+ if(cmd.type == CommandType::EXECUTE_COMMAND_BUFFERS)
+ {
+ for(auto secondaryCB : cmd.data.executeCommandBuffers.buffers)
+ {
+ for(auto command : secondaryCB->GetChildCommandsByType(mask))
+ {
+ mCommandStack.push_back(command);
+ }
+ }
+ }
+ }
+ return mCommandStack;
+}
+
} // namespace Dali
{
class TestGraphicsTexture;
class TestGraphicsBuffer;
+class TestGraphicsCommandBuffer;
class TestGraphicsSampler;
class TestGraphicsPipeline;
enum class CommandType
{
- FLUSH = 1 << 0,
- BIND_TEXTURES = 1 << 1,
- BIND_SAMPLERS = 1 << 2,
- BIND_VERTEX_BUFFERS = 1 << 3,
- BIND_INDEX_BUFFER = 1 << 4,
- BIND_UNIFORM_BUFFER = 1 << 5,
- BIND_PIPELINE = 1 << 6,
- DRAW = 1 << 7,
- DRAW_INDEXED = 1 << 8,
- DRAW_INDEXED_INDIRECT = 1 << 9,
- SET_SCISSOR = 1 << 10,
- SET_SCISSOR_TEST = 1 << 11,
- SET_VIEWPORT = 1 << 12,
- SET_VIEWPORT_TEST = 1 << 13
+ FLUSH = 1 << 0,
+ BIND_TEXTURES = 1 << 1,
+ BIND_SAMPLERS = 1 << 2,
+ BIND_VERTEX_BUFFERS = 1 << 3,
+ BIND_INDEX_BUFFER = 1 << 4,
+ BIND_UNIFORM_BUFFER = 1 << 5,
+ BIND_PIPELINE = 1 << 6,
+ DRAW = 1 << 7,
+ DRAW_INDEXED = 1 << 8,
+ DRAW_INDEXED_INDIRECT = 1 << 9,
+ SET_SCISSOR = 1 << 10,
+ SET_SCISSOR_TEST = 1 << 11,
+ SET_VIEWPORT = 1 << 12,
+ SET_VIEWPORT_TEST = 1 << 13,
+ BEGIN_RENDER_PASS = 1 << 14,
+ END_RENDER_PASS = 1 << 15,
+ EXECUTE_COMMAND_BUFFERS = 1 << 16,
+ SET_COLOR_MASK = 1 << 17,
+ CLEAR_STENCIL_BUFFER = 1 << 18,
+ CLEAR_DEPTH_BUFFER = 1 << 19,
+ SET_STENCIL_TEST_ENABLE = 1 << 20,
+ SET_STENCIL_WRITE_MASK = 1 << 21,
+ SET_STENCIL_OP = 1 << 22,
+ SET_STENCIL_FUNC = 1 << 23,
+ SET_DEPTH_COMPARE_OP = 1 << 24,
+ SET_DEPTH_TEST_ENABLE = 1 << 25,
+ SET_DEPTH_WRITE_ENABLE = 1 << 26,
};
+std::ostream& operator<<(std::ostream& os, Graphics::StencilOp op);
+
+std::ostream& operator<<(std::ostream& os, Graphics::CompareOp op);
+
using CommandTypeMask = uint32_t;
template<typename T>
inline CommandTypeMask operator|(T flags, CommandType bit)
{
}
+ Command(CommandType type)
+ : type(type)
+ {
+ // do non-trivial initialization
+ switch(type)
+ {
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor();
+ break;
+ }
+ default:
+ {
+ }
+ }
+ }
+
~Command()
{
+ switch(type)
+ {
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ data.beginRenderPass.~BeginRenderPassDescriptor();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
}
/**
{
switch(rhs.type)
{
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(rhs.data.beginRenderPass);
+ break;
+ }
+ case CommandType::END_RENDER_PASS:
+ {
+ data.endRenderPass = rhs.data.endRenderPass;
+ break;
+ }
+ case CommandType::EXECUTE_COMMAND_BUFFERS:
+ {
+ data.executeCommandBuffers = rhs.data.executeCommandBuffers;
+ break;
+ }
+
case CommandType::BIND_VERTEX_BUFFERS:
{
data.bindVertexBuffers = rhs.data.bindVertexBuffers;
data.viewportTest.enable = rhs.data.viewportTest.enable;
break;
}
+ case CommandType::SET_COLOR_MASK:
+ {
+ data.colorMask.enabled = rhs.data.colorMask.enabled;
+ break;
+ }
+ case CommandType::CLEAR_STENCIL_BUFFER:
+ {
+ break;
+ }
+ case CommandType::CLEAR_DEPTH_BUFFER:
+ {
+ break;
+ }
+ case CommandType::SET_STENCIL_TEST_ENABLE:
+ {
+ data.stencilTest.enabled = rhs.data.stencilTest.enabled;
+ break;
+ }
+ case CommandType::SET_STENCIL_FUNC:
+ {
+ data.stencilFunc.compareMask = rhs.data.stencilFunc.compareMask;
+ data.stencilFunc.compareOp = rhs.data.stencilFunc.compareOp;
+ data.stencilFunc.reference = rhs.data.stencilFunc.reference;
+ break;
+ }
+ case CommandType::SET_STENCIL_WRITE_MASK:
+ {
+ data.stencilWriteMask.mask = rhs.data.stencilWriteMask.mask;
+ break;
+ }
+ case CommandType::SET_STENCIL_OP:
+ {
+ data.stencilOp.failOp = rhs.data.stencilOp.failOp;
+ data.stencilOp.depthFailOp = rhs.data.stencilOp.depthFailOp;
+ data.stencilOp.passOp = rhs.data.stencilOp.passOp;
+ break;
+ }
+
+ case CommandType::SET_DEPTH_COMPARE_OP:
+ {
+ data.depth.compareOp = rhs.data.depth.compareOp;
+ break;
+ }
+ case CommandType::SET_DEPTH_TEST_ENABLE:
+ {
+ data.depth.testEnabled = rhs.data.depth.testEnabled;
+ break;
+ }
+ case CommandType::SET_DEPTH_WRITE_ENABLE:
+ {
+ data.depth.writeEnabled = rhs.data.depth.writeEnabled;
+ break;
+ }
}
type = rhs.type;
}
{
switch(rhs.type)
{
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(std::move(rhs.data.beginRenderPass));
+ break;
+ }
+ case CommandType::END_RENDER_PASS:
+ {
+ data.endRenderPass = std::move(rhs.data.endRenderPass);
+ break;
+ }
+ case CommandType::EXECUTE_COMMAND_BUFFERS:
+ {
+ data.executeCommandBuffers = std::move(rhs.data.executeCommandBuffers);
+ break;
+ }
case CommandType::BIND_VERTEX_BUFFERS:
{
data.bindVertexBuffers = std::move(rhs.data.bindVertexBuffers);
data.viewportTest.enable = rhs.data.viewportTest.enable;
break;
}
+
+ case CommandType::SET_COLOR_MASK:
+ {
+ data.colorMask.enabled = rhs.data.colorMask.enabled;
+ break;
+ }
+ case CommandType::CLEAR_STENCIL_BUFFER:
+ {
+ break;
+ }
+ case CommandType::CLEAR_DEPTH_BUFFER:
+ {
+ break;
+ }
+ case CommandType::SET_STENCIL_TEST_ENABLE:
+ {
+ data.stencilTest.enabled = rhs.data.stencilTest.enabled;
+ break;
+ }
+ case CommandType::SET_STENCIL_WRITE_MASK:
+ {
+ data.stencilWriteMask.mask = rhs.data.stencilWriteMask.mask;
+ break;
+ }
+ case CommandType::SET_STENCIL_OP:
+ {
+ data.stencilOp.failOp = rhs.data.stencilOp.failOp;
+ data.stencilOp.depthFailOp = rhs.data.stencilOp.depthFailOp;
+ data.stencilOp.passOp = rhs.data.stencilOp.passOp;
+ break;
+ }
+ case CommandType::SET_STENCIL_FUNC:
+ {
+ data.stencilFunc.compareMask = rhs.data.stencilFunc.compareMask;
+ data.stencilFunc.compareOp = rhs.data.stencilFunc.compareOp;
+ data.stencilFunc.reference = rhs.data.stencilFunc.reference;
+ break;
+ }
+ case CommandType::SET_DEPTH_COMPARE_OP:
+ {
+ data.depth.compareOp = rhs.data.depth.compareOp;
+ break;
+ }
+ case CommandType::SET_DEPTH_TEST_ENABLE:
+ {
+ data.depth.testEnabled = rhs.data.depth.testEnabled;
+ break;
+ }
+ case CommandType::SET_DEPTH_WRITE_ENABLE:
+ {
+ data.depth.writeEnabled = rhs.data.depth.writeEnabled;
+ break;
+ }
}
type = rhs.type;
}
{
bool enable;
} viewportTest;
+
+ struct BeginRenderPassDescriptor
+ {
+ Graphics::RenderPass* renderPass;
+ Graphics::RenderTarget* renderTarget;
+ Graphics::Rect2D renderArea;
+ std::vector<Graphics::ClearValue> clearValues;
+ } beginRenderPass;
+
+ struct
+ {
+ Graphics::SyncObject* syncObject;
+ } endRenderPass;
+
+ struct
+ {
+ std::vector<const TestGraphicsCommandBuffer*> buffers;
+ } executeCommandBuffers;
+
+ struct
+ {
+ Graphics::CompareOp compareOp;
+ bool testEnabled;
+ bool writeEnabled;
+ } depth;
+
+ struct
+ {
+ Graphics::StencilOp failOp;
+ Graphics::StencilOp passOp;
+ Graphics::StencilOp depthFailOp;
+ } stencilOp;
+
+ struct
+ {
+ uint32_t mask;
+ } stencilWriteMask;
+
+ struct
+ {
+ uint32_t compareMask;
+ Graphics::CompareOp compareOp;
+ uint32_t reference;
+ } stencilFunc;
+
+ struct
+ {
+ bool enabled;
+ } stencilTest;
+
+ struct
+ {
+ bool enabled;
+ } colorMask;
} data;
};
}
void BeginRenderPass(
- Graphics::RenderPass& renderPass,
- Graphics::RenderTarget& renderTarget,
- Graphics::Extent2D renderArea,
+ Graphics::RenderPass* renderPass,
+ Graphics::RenderTarget* renderTarget,
+ Graphics::Rect2D renderArea,
std::vector<Graphics::ClearValue> clearValues) override
{
- mCallStack.PushCall("BeginRenderPass", "");
+ mCommands.emplace_back(CommandType::BEGIN_RENDER_PASS);
+ auto& cmd = mCommands.back();
+ cmd.data.beginRenderPass.renderPass = renderPass;
+ cmd.data.beginRenderPass.renderTarget = renderTarget;
+ cmd.data.beginRenderPass.renderArea = renderArea;
+ cmd.data.beginRenderPass.clearValues = clearValues;
+
+ TraceCallStack::NamedParams namedParams;
+ namedParams["renderPass"] << std::hex << renderPass;
+ namedParams["renderTarget"] << std::hex << renderTarget;
+ namedParams["renderArea"] << renderArea.width << ", " << renderArea.height;
+ mCallStack.PushCall("BeginRenderPass", namedParams.str(), namedParams);
}
/**
* dependencies (for example, to know when target texture is ready
* before passing it to another render pass).
*/
- void EndRenderPass() override
+ void EndRenderPass(Graphics::SyncObject* syncObject) override
{
- mCallStack.PushCall("EndRenderPass", "");
+ mCommands.emplace_back(CommandType::END_RENDER_PASS);
+ auto& cmd = mCommands.back();
+
+ cmd.data.endRenderPass.syncObject = syncObject;
+
+ TraceCallStack::NamedParams namedParams;
+ namedParams["syncObject"] << std::hex << syncObject;
+ mCallStack.PushCall("EndRenderPass", namedParams.str(), namedParams);
+ }
+
+ void ExecuteCommandBuffers(std::vector<const CommandBuffer*>&& commandBuffers) override
+ {
+ mCommands.emplace_back();
+ auto& cmd = mCommands.back();
+ cmd.type = CommandType::EXECUTE_COMMAND_BUFFERS;
+ cmd.data.executeCommandBuffers.buffers.reserve(commandBuffers.size());
+ for(auto&& item : commandBuffers)
+ {
+ cmd.data.executeCommandBuffers.buffers.emplace_back(static_cast<const TestGraphicsCommandBuffer*>(item));
+ }
+ mCallStack.PushCall("ExecuteCommandBuffers", "");
}
void Draw(
mCommands.back().data.viewportTest.enable = value;
}
+ void SetColorMask(bool enabled) override
+ {
+ TraceCallStack::NamedParams params;
+ params["enabled"] << (enabled ? "T" : "F");
+ mCallStack.PushCall("SetColorMask", params.str(), params);
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_COLOR_MASK;
+ mCommands.back().data.colorMask.enabled = enabled;
+ }
+
+ void ClearStencilBuffer() override
+ {
+ mCallStack.PushCall("SetStencilMask", "");
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::CLEAR_STENCIL_BUFFER;
+ }
+
+ void SetStencilTestEnable(bool stencilEnable) override
+ {
+ TraceCallStack::NamedParams params;
+ params["enabled"] << (stencilEnable ? "T" : "F");
+ mCallStack.PushCall("SetStencilTestEnable", params.str(), params);
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_STENCIL_TEST_ENABLE;
+ mCommands.back().data.stencilTest.enabled = stencilEnable;
+ }
+
+ void SetStencilWriteMask(uint32_t writeMask) override
+ {
+ TraceCallStack::NamedParams params;
+ params["writeMask"] << std::hex << writeMask;
+ mCallStack.PushCall("SetStencilWriteMask", params.str(), params);
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_STENCIL_WRITE_MASK;
+ mCommands.back().data.stencilWriteMask.mask = writeMask;
+ }
+
+ void SetStencilOp(Graphics::StencilOp failOp,
+ Graphics::StencilOp passOp,
+ Graphics::StencilOp depthFailOp) override
+ {
+ TraceCallStack::NamedParams params;
+ params["failOp"] << failOp;
+ params["passOp"] << passOp;
+ params["depthFailOp"] << depthFailOp;
+ mCallStack.PushCall("SetStencilOp", params.str(), params);
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_STENCIL_OP;
+ mCommands.back().data.stencilOp.failOp = failOp;
+ mCommands.back().data.stencilOp.passOp = passOp;
+ mCommands.back().data.stencilOp.depthFailOp = depthFailOp;
+ }
+
+ void SetStencilFunc(Graphics::CompareOp compareOp,
+ uint32_t reference,
+ uint32_t compareMask) override
+ {
+ TraceCallStack::NamedParams params;
+ params["compareOp"] << compareOp;
+ params["compareMask"] << std::hex << compareMask;
+ params["reference"] << std::hex << reference;
+ mCallStack.PushCall("SetStencilFunc", params.str(), params);
+
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_STENCIL_FUNC;
+
+ mCommands.back().data.stencilFunc.compareOp = compareOp;
+ mCommands.back().data.stencilFunc.compareMask = compareMask;
+ mCommands.back().data.stencilFunc.reference = reference;
+ }
+
+ void SetDepthCompareOp(Graphics::CompareOp compareOp) override
+ {
+ TraceCallStack::NamedParams params;
+ params["compareOp"] << compareOp;
+ mCallStack.PushCall("SetDepthCompareOp", params.str(), params);
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_DEPTH_COMPARE_OP;
+ mCommands.back().data.depth.compareOp = compareOp;
+ }
+
+ void SetDepthTestEnable(bool depthTestEnable) override
+ {
+ TraceCallStack::NamedParams params;
+ params["enabled"] << (depthTestEnable ? "T" : "F");
+ mCallStack.PushCall("SetDepthTestEnable", params.str(), params);
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_DEPTH_TEST_ENABLE;
+ mCommands.back().data.depth.testEnabled = depthTestEnable;
+ }
+ void SetDepthWriteEnable(bool depthWriteEnable) override
+ {
+ TraceCallStack::NamedParams params;
+ params["enabled"] << (depthWriteEnable ? "T" : "F");
+ mCallStack.PushCall("SetDepthWriteEnable", params.str(), params);
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::SET_DEPTH_WRITE_ENABLE;
+ mCommands.back().data.depth.writeEnabled = depthWriteEnable;
+ }
+ void ClearDepthBuffer() override
+ {
+ mCallStack.PushCall("ClearDepthBuffer", "");
+ mCommands.emplace_back();
+ mCommands.back().type = CommandType::CLEAR_DEPTH_BUFFER;
+ }
+
[[nodiscard]] const std::vector<Command>& GetCommands() const
{
return mCommands;
/**
* Retrieves commands of specified type
*/
- std::vector<Command*> GetCommandsByType(CommandTypeMask mask);
+ std::vector<const Command*> GetCommandsByType(CommandTypeMask mask) const;
+
+ std::vector<const Command*> GetChildCommandsByType(CommandTypeMask mask) const;
private:
TraceCallStack& mCallStack;
#include "test-graphics-buffer.h"
#include "test-graphics-command-buffer.h"
+#include "test-graphics-framebuffer.h"
#include "test-graphics-reflection.h"
+#include "test-graphics-render-pass.h"
+#include "test-graphics-render-target.h"
#include "test-graphics-sampler.h"
#include "test-graphics-shader.h"
+#include "test-graphics-sync-object.h"
#include "test-graphics-texture.h"
#include <dali/integration-api/gl-defines.h>
namespace Dali
{
-template<typename T>
-T* Uncast(const Graphics::CommandBuffer* object)
-{
- return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Texture* object)
-{
- return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Sampler* object)
-{
- return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Buffer* object)
-{
- return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Shader* object)
-{
- return const_cast<T*>(static_cast<const T*>(object));
-}
-
std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo)
{
return o << "usage:" << std::hex << bufferCreateInfo.usage << ", size:" << std::dec << bufferCreateInfo.size;
return o;
}
-class TestGraphicsMemory : public Graphics::Memory
+std::ostream& operator<<(std::ostream& o, const Graphics::ColorAttachment& colorAttachment)
{
-public:
- TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
- : mCallStack(callStack),
- mBuffer(buffer),
- mMappedOffset(mappedOffset),
- mMappedSize(mappedSize),
- mLockedOffset(0u),
- mLockedSize(0u)
- {
- }
-
- void* LockRegion(uint32_t offset, uint32_t size) override
- {
- std::ostringstream o;
- o << offset << ", " << size;
- mCallStack.PushCall("Memory::LockRegion", o.str());
-
- if(offset > mMappedOffset + mMappedSize ||
- size + offset > mMappedOffset + mMappedSize)
- {
- fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
- mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
- }
- mLockedOffset = offset;
- mLockedSize = size;
- return &mBuffer.memory[mMappedOffset + offset];
- }
+ o << "attachmentId:" << colorAttachment.attachmentId
+ << " layerId:" << colorAttachment.layerId
+ << " levelId:" << colorAttachment.levelId
+ << " texture:" << colorAttachment.texture;
+ return o;
+}
- void Unlock(bool flush) override
- {
- mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
- if(flush)
- {
- Flush();
- }
- }
+std::ostream& operator<<(std::ostream& o, const Graphics::DepthStencilAttachment& depthStencilAttachment)
+{
+ o << "depthTexture:" << depthStencilAttachment.depthTexture
+ << "depthLevel:" << depthStencilAttachment.depthLevel
+ << "stencilTexture:" << depthStencilAttachment.stencilTexture
+ << "stencilLevel:" << depthStencilAttachment.stencilLevel;
+ return o;
+}
- void Flush() override
+std::ostream& operator<<(std::ostream& o, const Graphics::FramebufferCreateInfo& createInfo)
+{
+ o << "colorAttachments:";
+ for(auto i = 0u; i < createInfo.colorAttachments.size(); ++i)
{
- mCallStack.PushCall("Memory::Flush", "");
- mBuffer.Bind();
- mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
- mBuffer.Unbind();
+ o << "[" << i << "]=" << createInfo.colorAttachments[i] << " ";
}
-
- TraceCallStack& mCallStack;
- TestGraphicsBuffer& mBuffer;
- uint32_t mMappedOffset;
- uint32_t mMappedSize;
- uint32_t mLockedOffset;
- uint32_t mLockedSize;
-};
-
-TestGraphicsController::TestGraphicsController()
-: mCallStack(true, "TestGraphicsController."),
- mCommandBufferCallStack(true, "TestCommandBuffer.")
-{
- mCallStack.Enable(true);
- mCommandBufferCallStack.Enable(true);
- auto& trace = mGl.GetTextureTrace();
- trace.Enable(true);
- trace.EnableLogging(true);
+ o << "depthStencilAttachment:" << createInfo.depthStencilAttachment;
+ o << "size: " << createInfo.size;
+ return o;
}
int GetNumComponents(Graphics::VertexInputFormat vertexFormat)
return op;
}
+struct GLCompareOp
+{
+ constexpr explicit GLCompareOp(Graphics::CompareOp compareOp)
+ {
+ switch(compareOp)
+ {
+ case Graphics::CompareOp::NEVER:
+ op = GL_NEVER;
+ break;
+ case Graphics::CompareOp::LESS:
+ op = GL_LESS;
+ break;
+ case Graphics::CompareOp::EQUAL:
+ op = GL_EQUAL;
+ break;
+ case Graphics::CompareOp::LESS_OR_EQUAL:
+ op = GL_LEQUAL;
+ break;
+ case Graphics::CompareOp::GREATER:
+ op = GL_GREATER;
+ break;
+ case Graphics::CompareOp::NOT_EQUAL:
+ op = GL_NOTEQUAL;
+ break;
+ case Graphics::CompareOp::GREATER_OR_EQUAL:
+ op = GL_GEQUAL;
+ break;
+ case Graphics::CompareOp::ALWAYS:
+ op = GL_ALWAYS;
+ break;
+ }
+ }
+ GLenum op{GL_LESS};
+};
+
+struct GLStencilOp
+{
+ constexpr explicit GLStencilOp(Graphics::StencilOp stencilOp)
+ {
+ switch(stencilOp)
+ {
+ case Graphics::StencilOp::KEEP:
+ op = GL_KEEP;
+ break;
+ case Graphics::StencilOp::ZERO:
+ op = GL_ZERO;
+ break;
+ case Graphics::StencilOp::REPLACE:
+ op = GL_REPLACE;
+ break;
+ case Graphics::StencilOp::INCREMENT_AND_CLAMP:
+ op = GL_INCR;
+ break;
+ case Graphics::StencilOp::DECREMENT_AND_CLAMP:
+ op = GL_DECR;
+ break;
+ case Graphics::StencilOp::INVERT:
+ op = GL_INVERT;
+ break;
+ case Graphics::StencilOp::INCREMENT_AND_WRAP:
+ op = GL_INCR_WRAP;
+ break;
+ case Graphics::StencilOp::DECREMENT_AND_WRAP:
+ op = GL_DECR_WRAP;
+ break;
+ }
+ }
+ GLenum op{GL_KEEP};
+};
+
+class TestGraphicsMemory : public Graphics::Memory
+{
+public:
+ TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
+ : mCallStack(callStack),
+ mBuffer(buffer),
+ mMappedOffset(mappedOffset),
+ mMappedSize(mappedSize),
+ mLockedOffset(0u),
+ mLockedSize(0u)
+ {
+ }
+
+ void* LockRegion(uint32_t offset, uint32_t size) override
+ {
+ std::ostringstream o;
+ o << offset << ", " << size;
+ mCallStack.PushCall("Memory::LockRegion", o.str());
+
+ if(offset > mMappedOffset + mMappedSize ||
+ size + offset > mMappedOffset + mMappedSize)
+ {
+ fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
+ mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
+ }
+ mLockedOffset = offset;
+ mLockedSize = size;
+ return &mBuffer.memory[mMappedOffset + offset];
+ }
+
+ void Unlock(bool flush) override
+ {
+ mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
+ if(flush)
+ {
+ Flush();
+ }
+ }
+
+ void Flush() override
+ {
+ mCallStack.PushCall("Memory::Flush", "");
+ mBuffer.Bind();
+ mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
+ mBuffer.Unbind();
+ }
+
+ TraceCallStack& mCallStack;
+ TestGraphicsBuffer& mBuffer;
+ uint32_t mMappedOffset;
+ uint32_t mMappedSize;
+ uint32_t mLockedOffset;
+ uint32_t mLockedSize;
+};
+
+TestGraphicsController::TestGraphicsController()
+: mCallStack(true, "TestGraphicsController."),
+ mCommandBufferCallStack(true, "TestCommandBuffer."),
+ mFrameBufferCallStack(true, "TestFrameBuffer.")
+{
+ mCallStack.Enable(true);
+ mCommandBufferCallStack.Enable(true);
+ auto& trace = mGl.GetTextureTrace();
+ trace.Enable(true);
+ trace.EnableLogging(true);
+}
+
void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
{
TraceCallStack::NamedParams namedParams;
for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer)
{
auto commandBuffer = Uncast<TestGraphicsCommandBuffer>(graphicsCommandBuffer);
+ ProcessCommandBuffer(*commandBuffer);
+ }
+}
+
+void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer)
+{
+ bool scissorEnabled = false;
+ TestGraphicsFramebuffer* currentFramebuffer{nullptr};
+ TestGraphicsPipeline* currentPipeline{nullptr};
- auto value = commandBuffer->GetCommandsByType(0 | CommandType::BIND_TEXTURES);
- if(!value.empty())
+ for(auto& cmd : commandBuffer.GetCommands())
+ {
+ // process command
+ switch(cmd.type)
{
- // must be fixed
- for(auto& binding : value[0]->data.bindTextures.textureBindings)
+ case CommandType::FLUSH:
{
- if(binding.texture)
+ // Nothing to do here
+ break;
+ }
+ case CommandType::BIND_TEXTURES:
+ {
+ for(auto& binding : cmd.data.bindTextures.textureBindings)
{
- auto texture = Uncast<TestGraphicsTexture>(binding.texture);
-
- texture->Bind(binding.binding);
-
- if(binding.sampler)
+ if(binding.texture)
{
- auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
- if(sampler)
+ auto texture = Uncast<TestGraphicsTexture>(binding.texture);
+ texture->Bind(binding.binding);
+
+ if(binding.sampler)
{
- sampler->Apply(texture->GetTarget());
+ auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
+ if(sampler)
+ {
+ sampler->Apply(texture->GetTarget());
+ }
}
- }
- texture->Prepare(); // Ensure native texture is ready
+ texture->Prepare(); // Ensure native texture is ready
+ }
}
+ break;
}
- }
-
- // IndexBuffer binding,
- auto bindIndexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_INDEX_BUFFER);
- if(!bindIndexBufferCmds.empty())
- {
- auto& indexBufferBinding = bindIndexBufferCmds[0]->data.bindIndexBuffer;
- if(indexBufferBinding.buffer)
+ case CommandType::BIND_VERTEX_BUFFERS:
{
- auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
- buffer->Bind();
+ for(auto& binding : cmd.data.bindVertexBuffers.vertexBufferBindings)
+ {
+ auto graphicsBuffer = binding.buffer;
+ auto vertexBuffer = Uncast<TestGraphicsBuffer>(graphicsBuffer);
+ vertexBuffer->Bind();
+ }
+ break;
}
- }
-
- // VertexBuffer binding,
- auto bindVertexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_VERTEX_BUFFERS);
- if(!bindVertexBufferCmds.empty())
- {
- for(auto& binding : bindVertexBufferCmds[0]->data.bindVertexBuffers.vertexBufferBindings)
+ case CommandType::BIND_INDEX_BUFFER:
{
- auto graphicsBuffer = binding.buffer;
- auto vertexBuffer = Uncast<TestGraphicsBuffer>(graphicsBuffer);
- vertexBuffer->Bind();
+ auto& indexBufferBinding = cmd.data.bindIndexBuffer;
+ if(indexBufferBinding.buffer)
+ {
+ auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
+ buffer->Bind();
+ }
+ break;
}
- }
-
- bool scissorEnabled = false;
+ case CommandType::BIND_UNIFORM_BUFFER:
+ {
+ if(currentPipeline)
+ {
+ auto& bindings = cmd.data.bindUniformBuffers;
+ auto buffer = bindings.standaloneUniformsBufferBinding;
- auto scissorTestList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR_TEST);
- if(!scissorTestList.empty())
- {
- if(scissorTestList[0]->data.scissorTest.enable)
+ // based on reflection, issue gl calls
+ buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(currentPipeline->programState.program), bindings.standaloneUniformsBufferBinding);
+ }
+ break;
+ }
+ case CommandType::BIND_SAMPLERS:
{
- mGl.Enable(GL_SCISSOR_TEST);
- scissorEnabled = true;
+ break;
}
- else
+ case CommandType::BIND_PIPELINE:
{
- mGl.Disable(GL_SCISSOR_TEST);
+ currentPipeline = Uncast<TestGraphicsPipeline>(cmd.data.bindPipeline.pipeline);
+ BindPipeline(currentPipeline);
+ break;
+ }
+ case CommandType::DRAW:
+ {
+ if(currentPipeline)
+ {
+ mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
+ 0,
+ cmd.data.draw.draw.vertexCount);
+ }
+ break;
+ }
+ case CommandType::DRAW_INDEXED:
+ {
+ if(currentPipeline)
+ {
+ mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
+ static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+ }
+ break;
+ }
+ case CommandType::DRAW_INDEXED_INDIRECT:
+ {
+ if(currentPipeline)
+ {
+ mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
+ static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+ }
+ break;
+ }
+ case CommandType::SET_SCISSOR:
+ {
+ if(scissorEnabled)
+ {
+ auto& rect = cmd.data.scissor.region;
+ mGl.Scissor(rect.x, rect.y, rect.width, rect.height);
+ }
+ break;
+ }
+ case CommandType::SET_SCISSOR_TEST:
+ {
+ if(cmd.data.scissorTest.enable)
+ {
+ mGl.Enable(GL_SCISSOR_TEST);
+ scissorEnabled = true;
+ }
+ else
+ {
+ mGl.Disable(GL_SCISSOR_TEST);
+ scissorEnabled = false;
+ }
+ break;
+ }
+ case CommandType::SET_VIEWPORT_TEST:
+ {
+ break;
+ }
+ case CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
+ {
+ auto& rect = cmd.data.viewport.region;
+ mGl.Viewport(rect.x, rect.y, rect.width, rect.height);
+ break;
}
- }
-
- auto scissorList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR);
- if(!scissorList.empty() && scissorEnabled)
- {
- auto& rect = scissorList[0]->data.scissor.region;
- mGl.Scissor(rect.x, rect.y, rect.width, rect.height);
- }
- auto viewportList = commandBuffer->GetCommandsByType(0 | CommandType::SET_VIEWPORT);
- if(!viewportList.empty())
- {
- mGl.Viewport(viewportList[0]->data.viewport.region.x, viewportList[0]->data.viewport.region.y, viewportList[0]->data.viewport.region.width, viewportList[0]->data.viewport.region.height);
- }
+ case CommandType::SET_COLOR_MASK:
+ {
+ // Set all channels to the same mask
+ const bool mask = cmd.data.colorMask.enabled;
+ mGl.ColorMask(mask, mask, mask, mask);
+ break;
+ }
+ case CommandType::CLEAR_STENCIL_BUFFER:
+ {
+ mGl.Clear(GL_STENCIL_BUFFER_BIT);
+ break;
+ }
+ case CommandType::CLEAR_DEPTH_BUFFER:
+ {
+ mGl.Clear(GL_DEPTH_BUFFER_BIT);
+ break;
+ }
- // ignore viewport enable
+ case CommandType::SET_STENCIL_TEST_ENABLE:
+ {
+ if(cmd.data.stencilTest.enabled)
+ {
+ mGl.Enable(GL_STENCIL_TEST);
+ }
+ else
+ {
+ mGl.Disable(GL_STENCIL_TEST);
+ }
+ break;
+ }
- // Pipeline attribute setup
- auto bindPipelineCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_PIPELINE);
- if(!bindPipelineCmds.empty())
- {
- auto pipeline = bindPipelineCmds[0]->data.bindPipeline.pipeline;
- auto& vi = pipeline->vertexInputState;
- for(auto& attribute : vi.attributes)
+ case CommandType::SET_STENCIL_FUNC:
{
- mGl.EnableVertexAttribArray(attribute.location);
- uint32_t attributeOffset = attribute.offset;
- GLsizei stride = vi.bufferBindings[attribute.binding].stride;
-
- mGl.VertexAttribPointer(attribute.location,
- GetNumComponents(attribute.format),
- GetGlType(attribute.format),
- GL_FALSE, // Not normalized
- stride,
- reinterpret_cast<void*>(attributeOffset));
+ mGl.StencilFunc(GLCompareOp(cmd.data.stencilFunc.compareOp).op,
+ cmd.data.stencilFunc.reference,
+ cmd.data.stencilFunc.compareMask);
+ break;
}
- // Cull face setup
- auto& rasterizationState = pipeline->rasterizationState;
- if(rasterizationState.cullMode == Graphics::CullMode::NONE)
+ case CommandType::SET_STENCIL_WRITE_MASK:
{
- mGl.Disable(GL_CULL_FACE);
+ mGl.StencilMask(cmd.data.stencilWriteMask.mask);
+ break;
}
- else
+ case CommandType::SET_STENCIL_OP:
{
- mGl.Enable(GL_CULL_FACE);
- mGl.CullFace(GetCullFace(rasterizationState.cullMode));
+ mGl.StencilOp(GLStencilOp(cmd.data.stencilOp.failOp).op,
+ GLStencilOp(cmd.data.stencilOp.depthFailOp).op,
+ GLStencilOp(cmd.data.stencilOp.passOp).op);
+ break;
}
- mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
- // We don't modify glPolygonMode in our context/abstraction from GL_FILL (the GL default),
- // so it isn't present in the API (and won't have any tests!)
-
- // Blending setup
- auto& colorBlendState = pipeline->colorBlendState;
- if(colorBlendState.blendEnable)
+ case CommandType::SET_DEPTH_COMPARE_OP:
{
- mGl.Enable(GL_BLEND);
-
- mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
- GetBlendFactor(colorBlendState.dstColorBlendFactor),
- GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
- GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
- if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
+ mGl.DepthFunc(GLCompareOp(cmd.data.depth.compareOp).op);
+ break;
+ }
+ case CommandType::SET_DEPTH_TEST_ENABLE:
+ {
+ if(cmd.data.depth.testEnabled)
{
- mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
+ mGl.Enable(GL_DEPTH_TEST);
}
else
{
- mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
+ mGl.Disable(GL_DEPTH_TEST);
}
- mGl.BlendColor(colorBlendState.blendConstants[0],
- colorBlendState.blendConstants[1],
- colorBlendState.blendConstants[2],
- colorBlendState.blendConstants[3]);
+ break;
}
- else
+ case CommandType::SET_DEPTH_WRITE_ENABLE:
{
- mGl.Disable(GL_BLEND);
+ mGl.DepthMask(cmd.data.depth.writeEnabled);
+ break;
}
- // draw call
- auto topology = pipeline->inputAssemblyState.topology;
-
- // UniformBuffer binding (once we know pipeline)
- auto bindUniformBuffersCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_UNIFORM_BUFFER);
- if(!bindUniformBuffersCmds.empty())
+ case CommandType::EXECUTE_COMMAND_BUFFERS:
{
- auto buffer = bindUniformBuffersCmds[0]->data.bindUniformBuffers.standaloneUniformsBufferBinding;
-
- // based on reflection, issue gl calls
- buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(pipeline->programState.program));
+ // Process secondary command buffers
+ for(auto& buf : cmd.data.executeCommandBuffers.buffers)
+ {
+ ProcessCommandBuffer(*Uncast<TestGraphicsCommandBuffer>(buf));
+ }
+ break;
}
-
- auto drawCmds = commandBuffer->GetCommandsByType(0 |
- CommandType::DRAW |
- CommandType::DRAW_INDEXED_INDIRECT |
- CommandType::DRAW_INDEXED);
-
- if(!drawCmds.empty())
+ case CommandType::BEGIN_RENDER_PASS:
{
- if(drawCmds[0]->data.draw.type == DrawCallDescriptor::Type::DRAW_INDEXED)
+ auto renderTarget = Uncast<TestGraphicsRenderTarget>(cmd.data.beginRenderPass.renderTarget);
+
+ if(renderTarget)
{
- mGl.DrawElements(GetTopology(topology),
- static_cast<GLsizei>(drawCmds[0]->data.draw.drawIndexed.indexCount),
- GL_UNSIGNED_SHORT,
- reinterpret_cast<void*>(drawCmds[0]->data.draw.drawIndexed.firstIndex));
+ auto fb = renderTarget->mCreateInfo.framebuffer;
+ if(fb)
+ {
+ if(currentFramebuffer != fb)
+ {
+ currentFramebuffer = Uncast<TestGraphicsFramebuffer>(fb);
+ currentFramebuffer->Bind();
+ }
+ }
+ else
+ {
+ mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
}
else
{
- mGl.DrawArrays(GetTopology(topology), 0, drawCmds[0]->data.draw.draw.vertexCount);
+ mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
}
+
+ auto& clearValues = cmd.data.beginRenderPass.clearValues;
+ if(clearValues.size() > 0)
+ {
+ const auto renderPass = static_cast<TestGraphicsRenderPass*>(cmd.data.beginRenderPass.renderPass);
+ if(renderPass)
+ {
+ const auto& color0 = renderPass->attachments[0];
+ GLuint mask = 0;
+ if(color0.loadOp == Graphics::AttachmentLoadOp::CLEAR)
+ {
+ mask |= GL_COLOR_BUFFER_BIT;
+
+ // Set clear color (todo: cache it!)
+ // Something goes wrong here if Alpha mask is GL_TRUE
+ mGl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+ mGl.ClearColor(clearValues[0].color.r,
+ clearValues[0].color.g,
+ clearValues[0].color.b,
+ clearValues[0].color.a);
+ }
+
+ // check for depth stencil
+ if(renderPass->attachments.size() > 1)
+ {
+ const auto& depthStencil = renderPass->attachments.back();
+ if(depthStencil.loadOp == Graphics::AttachmentLoadOp::CLEAR)
+ {
+ mGl.DepthMask(true);
+ uint32_t depthClearColor = 0u;
+ if(clearValues.size() == renderPass->attachments.size())
+ {
+ depthClearColor = clearValues.back().depthStencil.depth;
+ }
+ mGl.ClearDepthf(depthClearColor);
+ mask |= GL_DEPTH_BUFFER_BIT;
+ }
+ if(depthStencil.stencilLoadOp == Graphics::AttachmentLoadOp::CLEAR)
+ {
+ uint32_t stencilClearColor = 0u;
+ if(clearValues.size() == renderPass->attachments.size())
+ {
+ stencilClearColor = clearValues.back().depthStencil.stencil;
+ }
+ mGl.ClearStencil(stencilClearColor);
+ mGl.StencilMask(0xFF); // Clear all the bitplanes (assume 8)
+ mask |= GL_STENCIL_BUFFER_BIT;
+ }
+ }
+
+ if(mask != 0)
+ {
+ // Test scissor area and RT size
+ const auto& area = cmd.data.beginRenderPass.renderArea;
+ if(area.x == 0 &&
+ area.y == 0 &&
+ renderTarget &&
+ area.width == renderTarget->mCreateInfo.extent.width &&
+ area.height == renderTarget->mCreateInfo.extent.height)
+ {
+ mGl.Disable(GL_SCISSOR_TEST);
+ mGl.Clear(mask);
+ }
+ else
+ {
+ mGl.Enable(GL_SCISSOR_TEST);
+ mGl.Scissor(cmd.data.beginRenderPass.renderArea.x, cmd.data.beginRenderPass.renderArea.y, cmd.data.beginRenderPass.renderArea.width, cmd.data.beginRenderPass.renderArea.height);
+ mGl.Clear(mask);
+ mGl.Disable(GL_SCISSOR_TEST);
+ }
+ }
+ }
+ else
+ {
+ DALI_ASSERT_DEBUG(0 && "BeginRenderPass has no render pass");
+ }
+ }
+ break;
}
- // attribute clear
- for(auto& attribute : vi.attributes)
+ case CommandType::END_RENDER_PASS:
{
- mGl.DisableVertexAttribArray(attribute.location);
+ if(cmd.data.endRenderPass.syncObject != nullptr)
+ {
+ auto syncObject = Uncast<TestGraphicsSyncObject>(cmd.data.endRenderPass.syncObject);
+ syncObject->InitializeResource(); // create the sync object.
+ }
+ break;
}
}
}
}
+void TestGraphicsController::BindPipeline(TestGraphicsPipeline* pipeline)
+{
+ auto& vi = pipeline->vertexInputState;
+ for(auto& attribute : vi.attributes)
+ {
+ mGl.EnableVertexAttribArray(attribute.location);
+ uint32_t attributeOffset = attribute.offset;
+ GLsizei stride = vi.bufferBindings[attribute.binding].stride;
+
+ mGl.VertexAttribPointer(attribute.location,
+ GetNumComponents(attribute.format),
+ GetGlType(attribute.format),
+ GL_FALSE, // Not normalized
+ stride,
+ reinterpret_cast<void*>(attributeOffset));
+ }
+
+ // Cull face setup
+ auto& rasterizationState = pipeline->rasterizationState;
+ if(rasterizationState.cullMode == Graphics::CullMode::NONE)
+ {
+ mGl.Disable(GL_CULL_FACE);
+ }
+ else
+ {
+ mGl.Enable(GL_CULL_FACE);
+ mGl.CullFace(GetCullFace(rasterizationState.cullMode));
+ }
+
+ mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
+
+ // Blending setup
+ auto& colorBlendState = pipeline->colorBlendState;
+ if(colorBlendState.blendEnable)
+ {
+ mGl.Enable(GL_BLEND);
+
+ mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
+ GetBlendFactor(colorBlendState.dstColorBlendFactor),
+ GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
+ GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
+ if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
+ {
+ mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
+ }
+ else
+ {
+ mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
+ }
+ mGl.BlendColor(colorBlendState.blendConstants[0],
+ colorBlendState.blendConstants[1],
+ colorBlendState.blendConstants[2],
+ colorBlendState.blendConstants[3]);
+ }
+ else
+ {
+ mGl.Disable(GL_BLEND);
+ }
+
+ auto* program = static_cast<const TestGraphicsProgram*>(pipeline->programState.program);
+ mGl.UseProgram(program->mImpl->mId);
+}
+
/**
* @brief Presents render target
* @param renderTarget render target to present
}
}
+void TestGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
+{
+ mCallStack.PushCall("GenerateTextureMipmaps", "");
+
+ auto gfxTexture = Uncast<TestGraphicsTexture>(&texture);
+ mGl.BindTexture(gfxTexture->GetTarget(), 0);
+ mGl.GenerateMipmap(gfxTexture->GetTarget());
+}
+
bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
{
TraceCallStack::NamedParams namedParams;
Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<Graphics::RenderPass>&& oldRenderPass)
{
mCallStack.PushCall("CreateRenderPass", "");
- return nullptr;
+ return Graphics::MakeUnique<TestGraphicsRenderPass>(mGl, renderPassCreateInfo);
}
Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Graphics::Texture>&& oldTexture)
return Graphics::MakeUnique<TestGraphicsTexture>(mGl, textureCreateInfo);
}
-Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(const Graphics::FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
+Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(
+ const Graphics::FramebufferCreateInfo& createInfo,
+ Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
{
- mCallStack.PushCall("CreateFramebuffer", "");
- return nullptr;
+ TraceCallStack::NamedParams namedParams;
+ namedParams["framebufferCreateInfo"] << createInfo;
+ mCallStack.PushCall("Controller::CreateFramebuffer", namedParams.str(), namedParams);
+
+ return Graphics::MakeUnique<TestGraphicsFramebuffer>(mFrameBufferCallStack, mGl, createInfo);
}
Graphics::UniquePtr<Graphics::Pipeline> TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
{
mCallStack.PushCall("CreateRenderTarget", "");
- return nullptr;
+ return Graphics::MakeUnique<TestGraphicsRenderTarget>(mGl, renderTargetCreateInfo);
+}
+
+Graphics::UniquePtr<Graphics::SyncObject> TestGraphicsController::CreateSyncObject(
+ const Graphics::SyncObjectCreateInfo& syncObjectCreateInfo,
+ Graphics::UniquePtr<Graphics::SyncObject>&& oldSyncObject)
+{
+ mCallStack.PushCall("CreateSyncObject", "");
+ return Graphics::MakeUnique<TestGraphicsSyncObject>(mGraphicsSyncImpl, syncObjectCreateInfo);
}
Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
#include <dali/graphics-api/graphics-controller.h>
#include "test-gl-abstraction.h"
#include "test-gl-context-helper-abstraction.h"
-#include "test-gl-sync-abstraction.h"
+#include "test-graphics-command-buffer.h"
#include "test-graphics-program.h"
#include "test-graphics-reflection.h"
+#include "test-graphics-sync-impl.h"
namespace Dali
{
std::ostream& operator<<(std::ostream& o, Graphics::SamplerMipmapMode mipmapMode);
std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& createInfo);
+template<typename T>
+T* Uncast(const Graphics::CommandBuffer* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Texture* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Sampler* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Buffer* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Shader* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Framebuffer* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Pipeline* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::RenderTarget* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::SyncObject* object)
+{
+ return const_cast<T*>(static_cast<const T*>(object));
+}
+
class TestGraphicsController : public Dali::Graphics::Controller
{
public:
return mGl;
}
- Integration::GlSyncAbstraction& GetGlSyncAbstraction() override
+ Integration::GlContextHelperAbstraction& GetGlContextHelperAbstraction() override
{
- return mGlSyncAbstraction;
+ return mGlContextHelperAbstraction;
}
- Integration::GlContextHelperAbstraction& GetGlContextHelperAbstraction() override
+ TestGraphicsSyncImplementation& GetGraphicsSyncImpl()
{
- return mGlContextHelperAbstraction;
+ return mGraphicsSyncImpl;
}
void SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo) override;
const std::vector<Graphics::TextureUpdateSourceInfo>& sourceList) override;
/**
+ * Auto generates mipmaps for the texture
+ * @param[in] texture The texture
+ */
+ void GenerateTextureMipmaps(const Graphics::Texture& texture) override;
+
+ /**
* TBD: do we need those functions in the new implementation?
*/
bool EnableDepthStencilBuffer(bool enableDepth, bool enableStencil) override;
Graphics::UniquePtr<Graphics::RenderTarget> CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget) override;
/**
+ * @brief Creates new sync object
+ * Could add timeout etc to createinfo... but nah.
+ *
+ * @return pointer to the SyncObject
+ */
+ Graphics::UniquePtr<Graphics::SyncObject> CreateSyncObject(const Graphics::SyncObjectCreateInfo& syncObjectCreateInfo,
+ Graphics::UniquePtr<Graphics::SyncObject>&& oldSyncObject) override;
+
+ /**
* @brief Maps memory associated with Buffer object
*
* @param[in] mapInfo Filled details of mapped resource
*
- * @return Returns pointer to Memory object or Graphicsnullptr on error
+ * @return Returns pointer to Memory object or nullptr on error
*/
Graphics::UniquePtr<Graphics::Memory> MapBufferRange(const Graphics::MapBufferInfo& mapInfo) override;
*/
bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
+ void ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer);
+
+ void BindPipeline(TestGraphicsPipeline* pipeline);
+
public:
mutable TraceCallStack mCallStack;
mutable TraceCallStack mCommandBufferCallStack;
+ mutable TraceCallStack mFrameBufferCallStack;
mutable std::vector<Graphics::SubmitInfo> mSubmitStack;
TestGlAbstraction mGl;
- TestGlSyncAbstraction mGlSyncAbstraction;
+ TestGraphicsSyncImplementation mGraphicsSyncImpl;
TestGlContextHelperAbstraction mGlContextHelperAbstraction;
bool isDiscardQueueEmptyResult{true};
};
std::vector<ProgramCache> mProgramCache;
+ struct PipelineCache
+ {
+ };
+
std::vector<UniformData> mCustomUniforms;
};
--- /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.
+ */
+
+#include "test-graphics-framebuffer.h"
+#include <dali/integration-api/gl-defines.h>
+#include "test-graphics-controller.h"
+#include "test-graphics-texture.h"
+
+namespace
+{
+const GLenum COLOR_ATTACHMENTS[] =
+ {
+ GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1,
+ GL_COLOR_ATTACHMENT2,
+ GL_COLOR_ATTACHMENT3,
+ GL_COLOR_ATTACHMENT4,
+ GL_COLOR_ATTACHMENT5,
+ GL_COLOR_ATTACHMENT6,
+ GL_COLOR_ATTACHMENT7,
+};
+
+struct DEPTH_STENCIL_ATTACHMENT_TYPE
+{
+ constexpr explicit DEPTH_STENCIL_ATTACHMENT_TYPE(Graphics::Format textureFormat)
+ {
+ switch(textureFormat)
+ {
+ case Graphics::Format::D16_UNORM:
+ case Graphics::Format::D32_SFLOAT:
+ case Graphics::Format::X8_D24_UNORM_PACK32:
+ {
+ attachment = GL_DEPTH_ATTACHMENT;
+ break;
+ }
+
+ case Graphics::Format::S8_UINT:
+ {
+ attachment = GL_STENCIL_ATTACHMENT;
+ break;
+ }
+
+ case Graphics::Format::D16_UNORM_S8_UINT:
+ case Graphics::Format::D24_UNORM_S8_UINT:
+ case Graphics::Format::D32_SFLOAT_S8_UINT:
+ {
+ attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+ break;
+ }
+ default:
+ {
+ attachment = GL_NONE;
+ break;
+ }
+ }
+ }
+ GLenum attachment{GL_NONE};
+};
+
+} // namespace
+//namespace
+
+namespace Dali
+{
+TestGraphicsFramebuffer::TestGraphicsFramebuffer(
+ TraceCallStack& callStack,
+ TestGlAbstraction& glAbstraction,
+ const Graphics::FramebufferCreateInfo& createInfo)
+: mGl(glAbstraction),
+ mCallStack(callStack)
+{
+ mCreateInfo.colorAttachments = std::move(createInfo.colorAttachments);
+ mCreateInfo.depthStencilAttachment = createInfo.depthStencilAttachment;
+ mCreateInfo.size = createInfo.size;
+}
+
+TestGraphicsFramebuffer::~TestGraphicsFramebuffer()
+{
+ if(mId)
+ {
+ mGl.DeleteFramebuffers(1, &mId);
+ }
+}
+
+void TestGraphicsFramebuffer::Initialize()
+{
+ mCallStack.PushCall("Initialize", "");
+
+ mGl.GenFramebuffers(1, &mId);
+ mGl.BindFramebuffer(GL_FRAMEBUFFER, mId);
+
+ for(Graphics::ColorAttachment& attachment : mCreateInfo.colorAttachments)
+ {
+ AttachTexture(attachment.texture, COLOR_ATTACHMENTS[attachment.attachmentId], attachment.layerId, attachment.levelId);
+ }
+ mGl.DrawBuffers(mCreateInfo.colorAttachments.size(), COLOR_ATTACHMENTS);
+
+ if(mCreateInfo.depthStencilAttachment.depthTexture)
+ {
+ // Create a depth or depth/stencil render target.
+ auto depthTexture = Uncast<TestGraphicsTexture>(mCreateInfo.depthStencilAttachment.depthTexture);
+ auto attachmentId = DEPTH_STENCIL_ATTACHMENT_TYPE(depthTexture->GetFormat()).attachment;
+
+ mGl.GenRenderbuffers(1, &mDepthBuffer);
+ mGl.BindRenderbuffer(GL_RENDERBUFFER, mDepthBuffer);
+ mGl.RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mCreateInfo.size.width, mCreateInfo.size.height);
+ mGl.FramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentId, GL_RENDERBUFFER, mDepthBuffer);
+
+ AttachTexture(depthTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.depthLevel);
+ }
+
+ if(mCreateInfo.depthStencilAttachment.stencilTexture)
+ {
+ auto stencilTexture = Uncast<TestGraphicsTexture>(mCreateInfo.depthStencilAttachment.stencilTexture);
+ auto attachmentId = DEPTH_STENCIL_ATTACHMENT_TYPE(stencilTexture->GetFormat()).attachment;
+
+ // Create a stencil render target.
+ mGl.GenRenderbuffers(1, &mStencilBuffer);
+ mGl.BindRenderbuffer(GL_RENDERBUFFER, mStencilBuffer);
+ mGl.RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, mCreateInfo.size.width, mCreateInfo.size.height);
+ mGl.FramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentId, GL_RENDERBUFFER, mStencilBuffer);
+
+ AttachTexture(stencilTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.stencilLevel);
+ }
+ mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void TestGraphicsFramebuffer::AttachTexture(Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId)
+{
+ auto graphicsTexture = Uncast<TestGraphicsTexture>(texture);
+ if(graphicsTexture->GetType() == Graphics::TextureType::TEXTURE_2D)
+ {
+ mGl.FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, graphicsTexture->GetTarget(), graphicsTexture->mId, levelId);
+ }
+ else
+ {
+ mGl.FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, GL_TEXTURE_CUBE_MAP_POSITIVE_X + layerId, graphicsTexture->mId, levelId);
+ }
+}
+
+void TestGraphicsFramebuffer::Bind()
+{
+ mCallStack.PushCall("Bind", "");
+
+ if(!mId)
+ {
+ Initialize();
+ }
+ mGl.BindFramebuffer(GL_FRAMEBUFFER, mId);
+}
+
+} // namespace Dali
--- /dev/null
+#ifndef TEST_GRAPHICS_FRAMEBUFFER_H
+#define TEST_GRAPHICS_FRAMEBUFFER_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.
+ */
+
+#include <dali/graphics-api/graphics-framebuffer-create-info.h>
+#include <dali/graphics-api/graphics-framebuffer.h>
+#include <dali/graphics-api/graphics-types.h>
+#include "test-gl-abstraction.h"
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+class TestGraphicsFramebuffer : public Graphics::Framebuffer
+{
+public:
+ TestGraphicsFramebuffer(TraceCallStack& callStack, TestGlAbstraction& glAbstraction, const Graphics::FramebufferCreateInfo& createInfo);
+ ~TestGraphicsFramebuffer();
+
+ void Initialize();
+ void AttachTexture(Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId);
+ void Bind();
+
+ TestGlAbstraction& mGl;
+ Graphics::FramebufferCreateInfo mCreateInfo;
+ TraceCallStack& mCallStack;
+
+ GLuint mId{0};
+ GLuint mDepthBuffer{0};
+ GLuint mStencilBuffer{0};
+};
+
+} // namespace Dali
+
+#endif //TEST_GRAPHICS_FRAMEBUFFER_H
TestGraphicsPipeline::TestGraphicsPipeline(TestGlAbstraction& gl, const Graphics::PipelineCreateInfo& createInfo)
: mGl(gl)
{
- // Need to deep copy, otherwise pointed at memory will go out of scope. Probably should do something about this.
+ // Need to deep copy, otherwise pointed at memory will go out of scope. @todo Probably should do something about this.
if(createInfo.colorBlendState)
colorBlendState = *createInfo.colorBlendState;
if(createInfo.viewportState)
viewportState = *createInfo.viewportState;
- if(createInfo.framebufferState)
- framebufferState = *createInfo.framebufferState;
-
if(createInfo.depthStencilState)
depthStencilState = *createInfo.depthStencilState;
--- /dev/null
+#ifndef DALI_TEST_GRAPHICS_RENDER_PASS_H
+#define DALI_TEST_GRAPHICS_RENDER_PASS_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.
+ */
+
+#include <dali/graphics-api/graphics-render-pass-create-info.h>
+#include <dali/graphics-api/graphics-render-pass.h>
+
+namespace Dali
+{
+class TestGraphicsRenderPass : public Graphics::RenderPass
+{
+public:
+ TestGraphicsRenderPass(TestGlAbstraction& gl, Graphics::RenderPassCreateInfo createInfo)
+ : mGl(gl)
+ {
+ attachments = *createInfo.attachments; // Deep copy the vector's contents... @todo FIXME!
+ }
+ ~TestGraphicsRenderPass() = default;
+
+ TestGlAbstraction& mGl;
+ std::vector<Graphics::AttachmentDescription> attachments;
+};
+
+} // namespace Dali
+
+#endif //DALI_TEST_GRAPHICS_RENDER_PASS_H
--- /dev/null
+#ifndef DALI_TEST_GRAPHICS_RENDER_TARGET_H
+#define DALI_TEST_GRAPHICS_RENDER_TARGET_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.
+ */
+
+#include <dali/graphics-api/graphics-render-target-create-info.h>
+#include <dali/graphics-api/graphics-render-target.h>
+
+namespace Dali
+{
+class TestGraphicsRenderTarget : public Graphics::RenderTarget
+{
+public:
+ TestGraphicsRenderTarget(TestGlAbstraction& gl, Graphics::RenderTargetCreateInfo createInfo)
+ : mGl(gl)
+ {
+ mCreateInfo.surface = createInfo.surface;
+ mCreateInfo.framebuffer = createInfo.framebuffer;
+ mCreateInfo.extent = createInfo.extent;
+ mCreateInfo.preTransform = createInfo.preTransform;
+ }
+ ~TestGraphicsRenderTarget() = default;
+
+ TestGlAbstraction& mGl;
+ Graphics::RenderTargetCreateInfo mCreateInfo;
+};
+
+} // namespace Dali
+
+#endif //DALI_TEST_GRAPHICS_RENDER_TARGET_H
*
*/
-#include "test-gl-sync-abstraction.h"
+#include "test-graphics-sync-impl.h"
namespace Dali
{
-TestSyncObject::TestSyncObject(TraceCallStack& trace)
+TestSyncObject::TestSyncObject(Dali::TraceCallStack& trace)
+
: synced(false),
mTrace(trace)
{
+ mTrace.PushCall("TestSyncObject cons", ""); // Trace the method
}
TestSyncObject::~TestSyncObject()
{
+ mTrace.PushCall("TestSyncObject dstr", ""); // Trace the method
}
bool TestSyncObject::IsSynced()
return synced;
}
-TestGlSyncAbstraction::TestGlSyncAbstraction()
+TestGraphicsSyncImplementation::TestGraphicsSyncImplementation()
{
Initialize();
}
/**
* Destructor
*/
-TestGlSyncAbstraction::~TestGlSyncAbstraction()
+TestGraphicsSyncImplementation::~TestGraphicsSyncImplementation()
{
for(SyncIter iter = mSyncObjects.begin(), end = mSyncObjects.end(); iter != end; ++iter)
{
}
/**
- * Initialize the sync objects - clear down the map
+ * Initialize the sync objects
*/
-void TestGlSyncAbstraction::Initialize()
+void TestGraphicsSyncImplementation::Initialize()
{
mSyncObjects.clear();
}
-/**
- * Create a sync object
- * @return the sync object
- */
-Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::CreateSyncObject()
+Integration::GraphicsSyncAbstraction::SyncObject* TestGraphicsSyncImplementation::CreateSyncObject()
{
mTrace.PushCall("CreateSyncObject", ""); // Trace the method
* Destroy a sync object
* @param[in] syncObject The object to destroy
*/
-void TestGlSyncAbstraction::DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject)
+void TestGraphicsSyncImplementation::DestroySyncObject(Integration::GraphicsSyncAbstraction::SyncObject* syncObject)
{
std::stringstream out;
out << syncObject;
}
}
-Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::GetLastSyncObject()
+Integration::GraphicsSyncAbstraction::SyncObject* TestGraphicsSyncImplementation::GetLastSyncObject()
{
if(!mSyncObjects.empty())
{
* @param[in]
* @param[in] sync The sync value to set
*/
-void TestGlSyncAbstraction::SetObjectSynced(Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync)
+void TestGraphicsSyncImplementation::SetObjectSynced(Integration::GraphicsSyncAbstraction::SyncObject* syncObject, bool sync)
{
TestSyncObject* testSyncObject = static_cast<TestSyncObject*>(syncObject);
testSyncObject->synced = sync;
/**
* Turn trace on
*/
-void TestGlSyncAbstraction::EnableTrace(bool enable)
+void TestGraphicsSyncImplementation::EnableTrace(bool enable)
{
mTrace.Enable(enable);
}
/**
* Reset the trace callstack
*/
-void TestGlSyncAbstraction::ResetTrace()
+void TestGraphicsSyncImplementation::ResetTrace()
{
mTrace.Reset();
}
/**
* Get the trace object (allows test case to find methods on it)
*/
-TraceCallStack& TestGlSyncAbstraction::GetTrace()
+TraceCallStack& TestGraphicsSyncImplementation::GetTrace()
{
return mTrace;
}
-int32_t TestGlSyncAbstraction::GetNumberOfSyncObjects()
+int32_t TestGraphicsSyncImplementation::GetNumberOfSyncObjects()
{
return static_cast<int32_t>(mSyncObjects.size());
}
-#ifndef TEST_GL_SYNC_ABSTRACTION_H
-#define TEST_GL_SYNC_ABSTRACTION_H
+#ifndef TEST_SYNC_IMPLEMENTATION_H
+#define TEST_SYNC_IMPLEMENTATION_H
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
#include <string>
// INTERNAL INCLUDES
+#include <dali/graphics-api/graphics-sync-object-create-info.h>
+#include <dali/graphics-api/graphics-sync-object.h>
#include <dali/integration-api/core.h>
-#include <dali/integration-api/gl-sync-abstraction.h>
+#include <dali/integration-api/graphics-sync-abstraction.h>
#include "test-trace-call-stack.h"
namespace Dali
{
-class DALI_CORE_API TestSyncObject : public Integration::GlSyncAbstraction::SyncObject
+class TestGraphicsSyncImplementation;
+
+class TestSyncObject : public Integration::GraphicsSyncAbstraction::SyncObject
{
public:
TestSyncObject(TraceCallStack& trace);
};
/**
- * Class to emulate the GL sync functions with tracing
+ * Class to emulate the gpu sync functions with tracing
*/
-class DALI_CORE_API TestGlSyncAbstraction : public Integration::GlSyncAbstraction
+class TestGraphicsSyncImplementation : public Integration::GraphicsSyncAbstraction
{
public:
/**
* Constructor
*/
- TestGlSyncAbstraction();
+ TestGraphicsSyncImplementation();
/**
* Destructor
*/
- ~TestGlSyncAbstraction() override;
+ virtual ~TestGraphicsSyncImplementation();
/**
- * Initialize the sync objects - clear down the map
+ * Initialize the sync objects
*/
void Initialize();
/**
- * Create a sync object
- * @return the sync object
+ * Create a sync object that can be polled
*/
- Integration::GlSyncAbstraction::SyncObject* CreateSyncObject() override;
+ GraphicsSyncAbstraction::SyncObject* CreateSyncObject() override;
/**
* Destroy a sync object
- * @param[in] syncObject The object to destroy
*/
- void DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject) override;
+ void DestroySyncObject(GraphicsSyncAbstraction::SyncObject* syncObject) override;
public: // TEST FUNCTIONS
- Integration::GlSyncAbstraction::SyncObject* GetLastSyncObject();
+ GraphicsSyncAbstraction::SyncObject* GetLastSyncObject();
/**
* Test method to trigger the object sync behaviour.
* @param[in]
* @param[in] sync The sync value to set
*/
- void SetObjectSynced(Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync);
+ void SetObjectSynced(GraphicsSyncAbstraction::SyncObject* syncObject, bool sync);
/**
* Turn trace on
*/
int32_t GetNumberOfSyncObjects();
-private:
- TestGlSyncAbstraction(const TestGlSyncAbstraction&); ///< Undefined
- TestGlSyncAbstraction& operator=(const TestGlSyncAbstraction&); ///< Undefined
+ TestGraphicsSyncImplementation(const TestGraphicsSyncImplementation&) = delete;
+ TestGraphicsSyncImplementation& operator=(const TestGraphicsSyncImplementation&) = delete;
+private:
typedef std::vector<TestSyncObject*> SyncContainer;
typedef SyncContainer::iterator SyncIter;
SyncContainer mSyncObjects; ///< The sync objects
--- /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.
+ */
+
+#include "test-graphics-sync-object.h"
+
+namespace Dali
+{
+TestGraphicsSyncObject::TestGraphicsSyncObject(TestGraphicsSyncImplementation& syncImpl, const Graphics::SyncObjectCreateInfo& createInfo)
+: mSyncImplementation(syncImpl),
+ mSyncObject(nullptr),
+ mCreateInfo(createInfo)
+{
+}
+
+TestGraphicsSyncObject::~TestGraphicsSyncObject()
+{
+ mSyncImplementation.DestroySyncObject(mSyncObject);
+}
+
+void TestGraphicsSyncObject::InitializeResource()
+{
+ mSyncObject = static_cast<TestSyncObject*>(mSyncImplementation.CreateSyncObject());
+}
+
+bool TestGraphicsSyncObject::IsSynced()
+{
+ bool synced = false;
+ if(mSyncObject)
+ {
+ synced = mSyncObject->IsSynced();
+ }
+ return synced;
+}
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TEST_GRAPHICS_SYNC_OBJECT_H_
+#define DALI_TEST_GRAPHICS_SYNC_OBJECT_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.
+ */
+
+#include <dali/graphics-api/graphics-sync-object-create-info.h>
+#include <dali/graphics-api/graphics-sync-object.h>
+
+#include <test-graphics-sync-impl.h>
+
+namespace Dali
+{
+class TestGraphicsSyncObject : public Graphics::SyncObject
+{
+public:
+ TestGraphicsSyncObject(TestGraphicsSyncImplementation& syncImpl, const Graphics::SyncObjectCreateInfo& createInfo);
+ ~TestGraphicsSyncObject() override;
+ void InitializeResource();
+ bool IsSynced() override;
+
+public:
+ TestGraphicsSyncImplementation& mSyncImplementation;
+ TestSyncObject* mSyncObject;
+ Graphics::SyncObjectCreateInfo mCreateInfo;
+};
+
+} // namespace Dali
+
+#endif //DALI_TEST_GRAPHICS_SYNC_OBJECT_H
case Graphics::Format::R64G64B64A64_SINT:
case Graphics::Format::R64G64B64A64_SFLOAT:
case Graphics::Format::B10G11R11_UFLOAT_PACK32:
+ case Graphics::Format::R11G11B10_UFLOAT_PACK32:
case Graphics::Format::E5B9G9R9_UFLOAT_PACK32:
case Graphics::Format::D16_UNORM:
case Graphics::Format::X8_D24_UNORM_PACK32:
glFormat = 0;
break;
}
+ case Graphics::Format::R11G11B10_UFLOAT_PACK32:
+ {
+ glFormat = GL_RGB;
+ pixelDataType = GL_FLOAT;
+ break;
+ }
case Graphics::Format::R4G4_UNORM_PACK8:
case Graphics::Format::A1R5G5B5_UNORM_PACK16:
{
case Graphics::Format::R16G16B16A16_SFLOAT:
case Graphics::Format::R32G32B32A32_SFLOAT:
+ case Graphics::Format::R11G11B10_UFLOAT_PACK32:
{
glInternalFormat = GL_R11F_G11F_B10F;
break;
GLuint GetTarget();
/**
+ * Get the texture type
+ */
+ Graphics::TextureType GetType()
+ {
+ return mCreateInfo.textureType;
+ }
+
+ /**
+ * Get the texture format
+ */
+ Graphics::Format GetFormat()
+ {
+ return mCreateInfo.format;
+ }
+
+ /**
* Bind this texture, ensure Native image is initialized if necessary.
*/
void Bind(uint32_t textureUnit);
#define DALI_TOOLKIT_SCENE_HOLDER_IMPL_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
bool PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect ) override { return false; };
- void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) override {};
+ void PostRender()
+ {
+ }
+
+ //void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) override {};
void StopRender() override {};
mScene = AdaptorImpl::GetScene( *mMainWindow );
mScene.SetDpi( Vector2( horizontalDpi, verticalDpi ) );
+ // Create render target for the scene
+ Graphics::RenderTargetCreateInfo rtInfo{};
+ rtInfo.SetExtent( {mSurfaceWidth, mSurfaceHeight });
+ mRenderTarget = mGraphicsController.CreateRenderTarget( rtInfo, nullptr );
+ mScene.SetSurfaceRenderTarget( mRenderTarget.get() );
+
// Core needs to be initialized next before we start the adaptor
InitializeCore();
Accessibility::Accessible::SetObjectRegistry(mCore->GetObjectRegistry());
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * 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.
#include <toolkit-vector-animation-renderer.h>
#include <toolkit-event-thread-callback.h>
#include <memory>
+#include <thread>
+#include <chrono>
namespace Dali
{
namespace Adaptor
{
+namespace
+{
+Dali::Internal::Adaptor::VectorAnimationRenderer* gVectorAnimationRenderer = nullptr;
+}
+
class VectorAnimationRenderer: public Dali::BaseObject
{
public:
mRenderer(),
mWidth( 0 ),
mHeight( 0 ),
+ mTotalFrameNumber(VECTOR_ANIMATION_TOTAL_FRAME_NUMBER),
mPreviousFrame( 0 ),
+ mDelayTime(0),
+ mDroppedFrames(0),
mFrameRate( 60.0f ),
+ mNeedDroppedFrames(false),
mEventThreadCallback( new EventThreadCallback( MakeCallback( this, &VectorAnimationRenderer::OnTriggered ) ) )
{
mCount++;
bool Load(const std::string& url)
{
mUrl = url;
- if(mUrl == "invalid.json")
+ if(mUrl == "invalid.json" || mUrl == "invalid.riv")
{
return false;
}
+ else if(mUrl == "framedrop.json")
+ {
+ // Change total frame number for test
+ mTotalFrameNumber = 200;
+ }
return true;
}
bool Render( uint32_t frameNumber )
{
+ if(mDelayTime != 0)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int32_t>(mDelayTime)));
+ mDelayTime = 0;
+ mNeedDroppedFrames = true;
+ }
+ else if(mNeedDroppedFrames)
+ {
+ mDroppedFrames = (frameNumber > mPreviousFrame) ? frameNumber - mPreviousFrame - 1: frameNumber + (mTotalFrameNumber - mPreviousFrame) - 1;
+ mNeedTrigger = true;
+ mNeedDroppedFrames = false;
+ }
+
if( mNeedTrigger )
{
mEventThreadCallback->Trigger();
uint32_t GetTotalFrameNumber() const
{
- return VECTOR_ANIMATION_TOTAL_FRAME_NUMBER;
+ return mTotalFrameNumber;
}
float GetFrameRate() const
Dali::Renderer mRenderer;
uint32_t mWidth;
uint32_t mHeight;
+ uint32_t mTotalFrameNumber;
uint32_t mPreviousFrame;
+ uint32_t mDelayTime;
+ uint32_t mDroppedFrames;
float mFrameRate;
+ bool mNeedDroppedFrames;
Dali::VectorAnimationRenderer::UploadCompletedSignalType mUploadCompletedSignal;
std::unique_ptr< EventThreadCallback > mEventThreadCallback;
};
{
Internal::Adaptor::VectorAnimationRenderer* animationRenderer = new Internal::Adaptor::VectorAnimationRenderer();
+ Internal::Adaptor::gVectorAnimationRenderer = animationRenderer;
+
return VectorAnimationRenderer( animationRenderer );
}
Dali::Internal::Adaptor::VectorAnimationRenderer::mNeedTrigger = true;
}
+void DelayRendering(uint32_t delay)
+{
+ Dali::Internal::Adaptor::gVectorAnimationRenderer->mDelayTime = delay;
+}
+
+uint32_t GetDroppedFrames()
+{
+ return Dali::Internal::Adaptor::gVectorAnimationRenderer->mDroppedFrames;
+}
+
} // VectorAnimationRenderer
} // Test
#define DALI_TOOLKIT_TEST_VECTOR_ANIMATION_RENDERER_H
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * 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.
#define VECTOR_ANIMATION_MARKER_END_FRAME_2 3
void RequestTrigger();
+void DelayRendering(uint32_t delay);
+uint32_t GetDroppedFrames();
} // VectorAnimationRenderer
} // Test
Dali::PixelData GetImageBuffer() override
{
- uint8_t* faviconData = new uint8_t[ 16 ];
- memset(faviconData, 0xff, 16);
- return Dali::PixelData::New( faviconData, 16, 2, 2,
- Dali::Pixel::Format::RGBA8888,
- Dali::PixelData::ReleaseFunction::DELETE_ARRAY );
+ uint8_t* imageData = new uint8_t[16];
+ memset(imageData, 0xff, 16);
+ return Dali::PixelData::New(imageData, 16, 2, 2,
+ Dali::Pixel::Format::RGBA8888,
+ Dali::PixelData::ReleaseFunction::DELETE_ARRAY);
}
private:
Dali::PixelData GetFavicon() const
{
- uint8_t* faviconData = new uint8_t[ 16 ];
-
- faviconData[ 0 ] = 0xff;
- faviconData[ 1 ] = 0x00;
- faviconData[ 2 ] = 0x00;
- faviconData[ 3 ] = 0xff;
- faviconData[ 4 ] = 0xff;
- faviconData[ 5 ] = 0x00;
- faviconData[ 6 ] = 0x00;
- faviconData[ 7 ] = 0xff;
- faviconData[ 8 ] = 0xff;
- faviconData[ 9 ] = 0x00;
- faviconData[ 10 ] = 0x00;
- faviconData[ 11 ] = 0xff;
- faviconData[ 12 ] = 0xff;
- faviconData[ 13 ] = 0x00;
- faviconData[ 14 ] = 0x00;
- faviconData[ 15 ] = 0xff;
-
- return Dali::PixelData::New( faviconData, 16, 2, 2,
- Dali::Pixel::Format::RGBA8888,
- Dali::PixelData::ReleaseFunction::DELETE_ARRAY );
+ static int testGetFaviconCount = 0;
+ if (testGetFaviconCount == 0)
+ {
+ testGetFaviconCount++;
+ uint8_t* faviconData = new uint8_t[16];
+ memset(faviconData, 0xff, 16);
+ return Dali::PixelData::New(faviconData, 16, 2, 2,
+ Dali::Pixel::Format::RGBA8888,
+ Dali::PixelData::ReleaseFunction::DELETE_ARRAY);
+ }
+ else
+ {
+ return Dali::PixelData();
+ }
}
bool CanGoForward() const
return mConsoleMessageSignal;
}
- Dali::WebEnginePlugin::WebEnginePolicyDecisionSignalType& PolicyDecisionSignal()
+ Dali::WebEnginePlugin::WebEngineResponsePolicyDecisionSignalType& ResponsePolicyDecisionSignal()
{
- return mPolicyDecisionSignal;
+ return mResponsePolicyDecisionSignal;
}
Dali::WebEnginePlugin::WebEngineCertificateSignalType& CertificateConfirmSignal()
Dali::WebEnginePlugin::WebEngineFrameRenderedSignalType mFrameRenderedSignal;
Dali::WebEnginePlugin::WebEngineRequestInterceptorSignalType mRequestInterceptorSignal;
Dali::WebEnginePlugin::WebEngineConsoleMessageSignalType mConsoleMessageSignal;
- Dali::WebEnginePlugin::WebEnginePolicyDecisionSignalType mPolicyDecisionSignal;
+ Dali::WebEnginePlugin::WebEngineResponsePolicyDecisionSignalType mResponsePolicyDecisionSignal;
Dali::WebEnginePlugin::WebEngineCertificateSignalType mCertificateConfirmSignal;
Dali::WebEnginePlugin::WebEngineCertificateSignalType mSslCertificateChangedSignal;
Dali::WebEnginePlugin::WebEngineHttpAuthHandlerSignalType mHttpAuthHandlerSignal;
std::shared_ptr<Dali::WebEngineConsoleMessage> message(new MockWebEngineConsoleMessage());
gInstance->mConsoleMessageSignal.Emit(std::move(message));
std::shared_ptr<Dali::WebEnginePolicyDecision> policyDecision(new MockWebEnginePolicyDecision());
- gInstance->mPolicyDecisionSignal.Emit(std::move(policyDecision));
+ gInstance->mResponsePolicyDecisionSignal.Emit(std::move(policyDecision));
std::shared_ptr<Dali::WebEngineCertificate> certificate(new MockWebEngineCertificate());
gInstance->mCertificateConfirmSignal.Emit(std::move(certificate));
return Internal::Adaptor::GetImplementation(*this).ConsoleMessageSignal();
}
-Dali::WebEnginePlugin::WebEnginePolicyDecisionSignalType& WebEngine::PolicyDecisionSignal()
+Dali::WebEnginePlugin::WebEngineResponsePolicyDecisionSignalType& WebEngine::ResponsePolicyDecisionSignal()
{
- return Internal::Adaptor::GetImplementation(*this).PolicyDecisionSignal();
+ return Internal::Adaptor::GetImplementation(*this).ResponsePolicyDecisionSignal();
}
Dali::WebEnginePlugin::WebEngineCertificateSignalType& WebEngine::CertificateConfirmSignal()
.Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
.Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
.Add( DevelVisual::Property::CORNER_RADIUS, 22.2f )
- .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE ));
+ .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE )
+ .Add( DevelVisual::Property::BORDERLINE_WIDTH, 33.3f )
+ .Add( DevelVisual::Property::BORDERLINE_COLOR, Color::RED )
+ .Add( DevelVisual::Property::BORDERLINE_OFFSET, 0.3f ));
Property::Map resultMap;
animatedImageVisual.CreatePropertyMap( resultMap );
DALI_TEST_CHECK( value );
DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::ABSOLUTE );
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), 33.3f, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<Vector4>(), Color::RED, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), 0.3f, TEST_LOCATION );
+
// request AnimatedImageVisual with an URL
Visual::Base animatedImageVisual2 = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
resultMap.Clear();
.Add( "wrapModeU", WrapMode::REPEAT )
.Add( "wrapModeV", WrapMode::DEFAULT )
.Add( "cornerRadius", Vector4(50.0f, 25.0f, 12.5f, 33.0f) )
- .Add( "cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE ));
+ .Add( "cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE )
+ .Add( "borderlineWidth", 20.0f )
+ .Add( "borderlineColor", Vector4() )
+ .Add( "borderlineOffset", -1.0f));
Property::Map resultMap;
animatedImageVisual.CreatePropertyMap( resultMap );
DALI_TEST_CHECK( value );
DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::RELATIVE );
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), 20.0f, TEST_LOCATION );
+
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4::ZERO, TEST_LOCATION );
+
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), -1.0f, TEST_LOCATION );
+
END_TEST;
}
DALI_TEST_CHECK( value );
DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::ABSOLUTE );
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<Vector4>(), Color::BLACK, TEST_LOCATION );
+
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
END_TEST;
}
.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, false )
+ .Add( DevelVisual::Property::BORDERLINE_WIDTH, 0.4f ));
Property::Map resultMap;
animatedImageVisual.CreatePropertyMap( resultMap );
DALI_TEST_CHECK( value );
DALI_TEST_EQUALS( value->Get<int>(), 4, TEST_LOCATION );
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), 0.4f, TEST_LOCATION );
+
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4(0.0f, 0.0f, 0.0f, 1.0f), TEST_LOCATION );
+
+ value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
END_TEST;
}
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
{
const char* TEST_VECTOR_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insta_camera.json";
+const char* TEST_VECTOR_IMAGE_FILE_NAME_FRAME_DROP = "framedrop.json";
const char* TEST_VECTOR_IMAGE_INVALID_FILE_NAME = "invalid.json";
+const char* TEST_VECTOR_IMAGE_RIVE_FILE_NAME = TEST_RESOURCE_DIR "/shape.riv";
+const char* TEST_VECTOR_IMAGE_INVALID_RIVE_FILE_NAME = "invalid.riv";
+
bool gAnimationFinishedSignalFired = false;
void VisualEventSignal( Control control, Dali::Property::Index visualIndex, Dali::Property::Index signalId )
.Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME )
.Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
.Add( DevelImageVisual::Property::PLAY_RANGE, playRange )
- .Add( DevelVisual::Property::CORNER_RADIUS, 50.0f );
+ .Add( DevelVisual::Property::CORNER_RADIUS, 50.0f )
+ .Add( DevelVisual::Property::BORDERLINE_WIDTH, 20.0f );
Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
DALI_TEST_CHECK( visual );
int startFrame = 1, endFrame = 3;
float cornerRadius = 22.0f;
+ float borderlineWidth = 2.0f;
+ Vector4 borderlineColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
+ float borderlineOffset = 0.1f;
Property::Array playRange;
playRange.PushBack( startFrame );
playRange.PushBack( endFrame );
.Add( "stopBehavior", DevelImageVisual::StopBehavior::FIRST_FRAME )
.Add( "loopingMode", DevelImageVisual::LoopingMode::AUTO_REVERSE )
.Add( "redrawInScalingDown", false )
- .Add( "cornerRadius", cornerRadius );
+ .Add( "cornerRadius", cornerRadius )
+ .Add( "borderlineWidth", borderlineWidth )
+ .Add( "borderlineColor", borderlineColor )
+ .Add( "borderlineOffset", borderlineOffset );
Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
DALI_TEST_CHECK( visual );
DALI_TEST_CHECK( value );
DALI_TEST_CHECK( value->Get< int >() == Visual::Transform::Policy::ABSOLUTE );
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get< float >(), borderlineWidth, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get< Vector4 >(), borderlineColor, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get< float >(), borderlineOffset, TEST_LOCATION );
+
actor.Unparent( );
DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
int startFrame = 1, endFrame = 3;
Vector4 cornerRadius(50.0f, 22.0f, 0.0f, 3.0f);
+ float borderlineWidth = 2.3f;
+ Vector4 borderlineColor = Vector4(0.3f, 0.3f, 1.0f, 1.0f);
+ float borderlineOffset = 0.3f;
Property::Array playRange;
playRange.PushBack( startFrame );
playRange.PushBack( endFrame );
.Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
.Add( DevelImageVisual::Property::PLAY_RANGE, playRange )
.Add( DevelVisual::Property::CORNER_RADIUS, cornerRadius )
- .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::RELATIVE);
+ .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::RELATIVE)
+ .Add( DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth )
+ .Add( DevelVisual::Property::BORDERLINE_COLOR, borderlineColor )
+ .Add( DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset );
// request AnimatedVectorImageVisual with a property map
VisualFactory factory = VisualFactory::Get();
DALI_TEST_CHECK( value );
DALI_TEST_CHECK( value->Get< int >() == Visual::Transform::Policy::RELATIVE );
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get< float >(), borderlineWidth, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get< Vector4 >(), borderlineColor, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get< float >(), borderlineOffset, TEST_LOCATION );
+
// request AnimatedVectorImageVisual with an URL
Visual::Base visual2 = factory.CreateVisual( TEST_VECTOR_IMAGE_FILE_NAME, ImageDimensions() );
END_TEST;
}
+
+int UtcDaliAnimatedVectorImageVisualFrameDrops(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliAnimatedVectorImageVisualFrameDrops");
+
+ Property::Map propertyMap;
+ propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+ .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME_FRAME_DROP);
+
+ Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ DummyControl actor = DummyControl::New(true);
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+ Vector2 controlSize(20.f, 30.f);
+ actor.SetProperty(Actor::Property::SIZE, controlSize);
+
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ Property::Map attributes;
+ DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
+
+ application.SendNotification();
+ application.Render();
+
+ // Trigger count is 1 - render the first frame
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ // Make delay to drop frames
+ Test::VectorAnimationRenderer::DelayRendering(170); // longer than 16.6 * 10frames
+
+ // Check dropped frame
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ uint32_t frames = Test::VectorAnimationRenderer::GetDroppedFrames();
+ DALI_TEST_CHECK(frames >= 9);
+
+ END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualLoadRiveFileP(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcDaliAnimatedVectorImageVisualLoadRiveFile: Request animated vector image visual with a rive url" );
+
+ VisualFactory factory = VisualFactory::Get();
+ Visual::Base visual = factory.CreateVisual( TEST_VECTOR_IMAGE_RIVE_FILE_NAME, ImageDimensions() );
+ DALI_TEST_CHECK( visual );
+
+ 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.0f, 200.0f ) );
+ application.GetScene().Add( actor );
+
+ application.SendNotification();
+ application.Render();
+
+ // renderer is added to actor
+ DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+ Renderer renderer = actor.GetRendererAt( 0u );
+ DALI_TEST_CHECK( renderer );
+
+ // Test SetOffScene().
+ actor.Unparent();
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualLoadRiveFileN(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("Request loading with invalid rive file - should draw broken image");
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ Property::Map propertyMap;
+ propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+ .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_INVALID_RIVE_FILE_NAME);
+
+ Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ 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(20.0f, 20.0f));
+
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ // Check resource status
+ Visual::ResourceStatus status = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL);
+ DALI_TEST_EQUALS(status, Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ // The broken image should be shown.
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualPlaybackRiveFile(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline( "UtcDaliAnimatedVectorImageVisualPlaybackRiveFile" );
+
+ {
+ // request AnimatedVectorImageVisual for Rive with a property map
+ VisualFactory factory = VisualFactory::Get();
+ Visual::Base visual = factory.CreateVisual(
+ Property::Map()
+ .Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+ .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_RIVE_FILE_NAME ) );
+
+ DummyControl dummyControl = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummyControl.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+ dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+ Property::Map attributes;
+ tet_infoline( "Test Play action" );
+ DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+ application.GetScene().Add( dummyControl );
+ application.SendNotification();
+ application.Render( 16 );
+
+ Property::Map map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ Property::Value* value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+ tet_infoline( "Test Pause action" );
+ DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, attributes );
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PAUSED );
+
+ tet_infoline( "Test Play action" );
+ DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+ tet_infoline( "Test Stop action" );
+ DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+ tet_infoline( "Test Stop action again" );
+ DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+ tet_infoline( "Test Play action" );
+ DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+ tet_infoline( "Off stage" );
+ dummyControl.Unparent();
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+ tet_infoline( "On stage again" );
+ application.GetScene().Add( dummyControl );
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+ tet_infoline( "Test Play action" );
+ DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+ application.SendNotification();
+ application.Render(16);
+
+ map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+ DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+ // Change Size
+ Vector3 newSize( 100.0f, 100.0f, 0.0f );
+ dummyControl.SetProperty( Actor::Property::SIZE, newSize );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // Size should be changed
+ Vector3 naturalSize = dummyControl.GetNaturalSize();
+ DALI_TEST_CHECK( naturalSize == newSize );
+
+ dummyControl.Unparent();
+ }
+
+ END_TEST;
+}
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
ToolkitTestApplication application;
Control control = Control::New();
+ control[Actor::Property::SIZE] = Vector2(100.0f, 100.0f);
application.GetScene().Add( control );
- tet_infoline( "Set transparent, no renderers should be created" );
- control.SetBackgroundColor( Color::TRANSPARENT );
- application.SendNotification();
- application.Render();
- DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
-
- tet_infoline( "Set transparent alpha with positive RGB values, no renderers should be created, but returned color should reflect what we set" );
- const Vector4 alphaZero( 1.0f, 0.5f, 0.25f, 0.0f );
- control.SetBackgroundColor( alphaZero );
- application.SendNotification();
- application.Render();
- DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
- DALI_TEST_EQUALS( GetControlBackgroundColor( control ), alphaZero, TEST_LOCATION );
-
tet_infoline( "Set semi transparent alpha with positive RGB values, 1 renderer should be created, but returned color should reflect what we set" );
const Vector4 semiTransparent( 1.0f, 0.75f, 0.5f, 0.5f );
control.SetBackgroundColor( semiTransparent );
DALI_TEST_EQUALS( GetControlBackgroundColor( control ), newColor, TEST_LOCATION );
DALI_TEST_EQUALS( renderer, control.GetRendererAt( 0 ), TEST_LOCATION );
- tet_infoline( "Set transparent, ensure no renderers are created" );
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = gl.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ tet_infoline( "Set transparent, 1 renderer should be created, but ensure nothing is drawn" );
control.SetBackgroundColor( Color::TRANSPARENT );
application.SendNotification();
application.Render();
- DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+ DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION);
+
+ drawTrace.Reset();
tet_infoline( "Set control to clip its children, a renderer should be created which will be transparent" );
control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
application.SendNotification();
application.Render();
+
DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+ DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION);
tet_infoline( "Set a color, only 1 renderer should exist" );
control.SetBackgroundColor( Color::RED );
DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
- tet_infoline( "Disable clipping, no renderers" );
+ drawTrace.Reset();
+
+ tet_infoline( "Disable clipping, render nothing" );
control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::DISABLED );
application.SendNotification();
application.Render();
- DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+ DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION);
END_TEST;
}
static int gResourceReadySignalCounter = 0;
-void OnResourceReadySignal( Control control )
+void OnResourceReadySignal01( Control control )
{
gResourceReadySignalCounter++;
}
}
-void OnResourceReadySignal01( Control control )
+void OnResourceReadySignal02( Control control )
{
if(++gResourceReadySignalCounter == 1)
{
}
}
+ImageView gImageView1;
+ImageView gImageView2;
+ImageView gImageView3;
+
+void OnResourceReadySignal03( Control control )
+{
+ if(gResourceReadySignalCounter == 0)
+ {
+ // Queue loading
+ // 1. Use cached image, then UploadComplete will be called right after OnResourceReadySignal03.
+ gImageView2[ImageView::Property::IMAGE] = gImage_34_RGBA;
+
+ // 2. Load a new image
+ gImageView3[ImageView::Property::IMAGE] = TEST_IMAGE_1;
+
+ // 3. Use the new image again
+ gImageView1[ImageView::Property::IMAGE] = TEST_IMAGE_1;
+ gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal03);
+ }
+ else if(gResourceReadySignalCounter == 1)
+ {
+ // This is called from TextureManager::ProcessQueuedTextures().
+ gImageView1.Unparent();
+ gImageView1.Reset();
+ }
+ gResourceReadySignalCounter++;
+}
+
}
int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
gResourceReadySignalCounter = 0;
ImageView imageView = ImageView::New( gImage_34_RGBA );
- imageView.ResourceReadySignal().Connect( &OnResourceReadySignal );
+ imageView.ResourceReadySignal().Connect( &OnResourceReadySignal01 );
application.GetScene().Add( imageView );
gResourceReadySignalCounter = 0;
ImageView imageView = ImageView::New( gImage_34_RGBA );
- imageView.ResourceReadySignal().Connect( &OnResourceReadySignal01 );
+ imageView.ResourceReadySignal().Connect( &OnResourceReadySignal02 );
application.GetScene().Add( imageView );
END_TEST;
}
+
+int UtcDaliImageViewSetImageOnResourceReadySignal03(void)
+{
+ tet_infoline("Test setting image from within signal handler.");
+
+ ToolkitTestApplication application;
+
+ gResourceReadySignalCounter = 0;
+
+ gImageView1 = ImageView::New(gImage_34_RGBA);
+ application.GetScene().Add(gImageView1);
+
+ // Wait for loading
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ gImageView2 = ImageView::New(gImage_600_RGB);
+ gImageView2.ResourceReadySignal().Connect(&OnResourceReadySignal03);
+ application.GetScene().Add(gImageView2);
+
+ gImageView3 = ImageView::New();
+ application.GetScene().Add(gImageView3);
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ END_TEST;
+}
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/public-api/image-loader/image.h>
#include <dali-toolkit/dali-toolkit.h>
#include "dummy-control.h"
END_TEST;
}
+
+int UtcDaliImageVisualWithNativeImage(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Use Native Image as url" );
+
+ NativeImageSourcePtr nativeImageSource = NativeImageSource::New(500, 500, NativeImageSource::COLOR_DEPTH_DEFAULT);
+ std::string url = Dali::Toolkit::Image::GenerateUrl(nativeImageSource);
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, url );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+ application.GetScene().Add( actor );
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+
+ Renderer renderer = actor.GetRendererAt(0);
+ Shader shader = renderer.GetShader();
+
+ Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+ DALI_TEST_CHECK(value.GetType() == Property::MAP);
+ const Property::Map* outMap = value.GetMap();
+ std::string fragmentShader = (*outMap)["fragment"].Get<std::string>();
+
+ const char* fragmentPrefix = nativeImageSource->GetCustomFragmentPrefix();
+ size_t pos = fragmentShader.find(fragmentPrefix);
+
+ DALI_TEST_EQUALS( pos != std::string::npos, true, TEST_LOCATION );
+
+ END_TEST;
+}
+
int UtcDaliImageVisualTextureReuse1(void)
{
ToolkitTestApplication application;
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
END_TEST;
}
+int UtcDaliKeyboardFocusManagerWithoutFocusablePropertiesMoveFocus(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" UtcDaliKeyboardFocusManagerWithoutFocusablePropertiesMoveFocus");
+
+ // Register Type
+ TypeInfo type;
+ type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+ DALI_TEST_CHECK( type );
+ BaseHandle handle = type.CreateInstance();
+ DALI_TEST_CHECK( handle );
+
+ KeyboardFocusManager manager = KeyboardFocusManager::Get();
+ DALI_TEST_CHECK(manager);
+
+ bool focusChangedSignalVerified = false;
+ FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+ manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+ PushButton button1 = PushButton::New();
+ PushButton button2 = PushButton::New();
+ PushButton button3 = PushButton::New();
+ PushButton button4 = PushButton::New();
+ PushButton button5 = PushButton::New();
+
+ button1.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+ button2.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+ button3.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+ button4.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+ button5.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+
+ button1.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+ button2.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+ button3.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+ button4.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+ button5.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+
+ application.GetScene().Add(button1);
+ application.GetScene().Add(button2);
+ application.GetScene().Add(button3);
+ application.GetScene().Add(button4);
+ application.GetScene().Add(button5);
+
+ // set position
+ // button1 -- button2
+ // | |
+ // | button5|
+ // button3 -- button4
+ button1.SetProperty( Actor::Property::POSITION, Vector2(0.0f, 0.0f));
+ button2.SetProperty( Actor::Property::POSITION, Vector2(100.0f, 0.0f));
+ button3.SetProperty( Actor::Property::POSITION, Vector2(0.0f, 100.0f));
+ button4.SetProperty( Actor::Property::POSITION, Vector2(100.0f, 100.0f));
+ button5.SetProperty( Actor::Property::POSITION, Vector2(60.0f, 60.0f));
+
+ // flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+ // Set the focus to the button1
+ // [button1] -- button2
+ // | |
+ // | button5|
+ // button3 -- button4
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(button1) == true);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == button1);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+ focusChangedCallback.Reset();
+
+ // without set the navigation properties, but we can focus move
+
+ // Move the focus towards right
+ // button1 -- [button2]
+ // | |
+ // | button5|
+ // button3 -- button4
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+
+ // Confirm whether focus is moved to button2
+ DALI_TEST_EQUALS(button2.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button1);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button2);
+ focusChangedCallback.Reset();
+
+ // Move the focus towards down
+ // button1 -- button2
+ // | |
+ // | [button5]|
+ // button3 -- button4
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::DOWN) == true);
+
+ // Confirm whether focus is moved to button5
+ DALI_TEST_EQUALS(button5.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button2);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button5);
+ focusChangedCallback.Reset();
+
+ // Move the focus towards right
+ // button1 -- button2
+ // | |
+ // | button5|
+ // button3 -- [button4]
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+
+ // Confirm whether focus is moved to button4
+ DALI_TEST_EQUALS(button4.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button5);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button4);
+ focusChangedCallback.Reset();
+
+ // Move the focus towards left
+ // button1 -- button2
+ // | |
+ // | [button5]|
+ // button3 -- button4
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+
+ // Confirm whether focus is moved to button5
+ DALI_TEST_EQUALS(button5.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button4);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button5);
+ focusChangedCallback.Reset();
+
+ // Move the focus towards left
+ // button1 -- button2
+ // | |
+ // | button5|
+ //[button3] -- button4
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+
+ // Confirm whether focus is moved to button3
+ DALI_TEST_EQUALS(button3.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button5);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button3);
+ focusChangedCallback.Reset();
+
+ // Move the focus towards up
+ //[button1]-- button2
+ // | |
+ // | button5|
+ // button3 -- button4
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == true);
+
+ // Confirm whether focus is moved to button1
+ DALI_TEST_EQUALS(button1.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button3);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+ focusChangedCallback.Reset();
+
+
+ // Move the focus towards left. The focus move will fail as no way to move it upwards
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == false);
+
+ // Move the focus toward page up/down. The focus move will fail as invalid direction.
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::PAGE_UP) == false);
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::PAGE_DOWN) == false);
+ focusChangedCallback.Reset();
+
+ END_TEST;
+}
#include <dali-toolkit/dali-toolkit.h>
#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>
using namespace Dali;
using namespace Toolkit;
const char* const PROPERTY_NAME_MAX_LENGTH = "maxLength";
const char* const PROPERTY_NAME_FONT_SIZE_SCALE = "fontSizeScale";
const char* const PROPERTY_NAME_GRAB_HANDLE_COLOR = "grabHandleColor";
-
+const char* const PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP = "enableGrabHandlePopup";
+const char* const PROPERTY_NAME_INPUT_METHOD_SETTINGS = "inputMethodSettings";
const Vector4 PLACEHOLDER_TEXT_COLOR( 0.8f, 0.8f, 0.8f, 0.8f );
const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color.
DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_MATCH_SYSTEM_LANGUAGE_DIRECTION ) == DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION );
DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_MAX_LENGTH ) == DevelTextEditor::Property::MAX_LENGTH );
DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_COLOR ) == DevelTextEditor::Property::GRAB_HANDLE_COLOR );
-
+ DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP ) == DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP );
+ DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_METHOD_SETTINGS ) == DevelTextEditor::Property::INPUT_METHOD_SETTINGS );
END_TEST;
}
editor.SetProperty( DevelTextEditor::Property::GRAB_HANDLE_COLOR, Color::GREEN );
DALI_TEST_EQUALS( editor.GetProperty<Vector4>( DevelTextEditor::Property::GRAB_HANDLE_COLOR ), Color::GREEN, TEST_LOCATION );
+ // Test the ENABLE_GRAB_HANDLE_POPUP property
+ editor.SetProperty( DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP, false );
+ DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP ), false, TEST_LOCATION);
+
+ // Check the input method setting
+ Property::Map propertyMap;
+ InputMethod::PanelLayout::Type panelLayout = InputMethod::PanelLayout::NUMBER;
+ InputMethod::AutoCapital::Type autoCapital = InputMethod::AutoCapital::WORD;
+ InputMethod::ButtonAction::Type buttonAction = InputMethod::ButtonAction::GO;
+ int inputVariation = 1;
+ propertyMap["PANEL_LAYOUT"] = panelLayout;
+ propertyMap["AUTO_CAPITALIZE"] = autoCapital;
+ propertyMap["BUTTON_ACTION"] = buttonAction;
+ propertyMap["VARIATION"] = inputVariation;
+ editor.SetProperty( DevelTextEditor::Property::INPUT_METHOD_SETTINGS, propertyMap );
+
+ Property::Value value = editor.GetProperty( DevelTextEditor::Property::INPUT_METHOD_SETTINGS );
+ Property::Map map;
+ DALI_TEST_CHECK( value.Get( map ) );
+
+ int layout = 0;
+ DALI_TEST_CHECK( map[ "PANEL_LAYOUT" ].Get( layout ) );
+ DALI_TEST_EQUALS( static_cast<int>(panelLayout), layout, TEST_LOCATION );
+
+ int capital = 0;
+ DALI_TEST_CHECK( map[ "AUTO_CAPITALIZE" ].Get( capital ) );
+ DALI_TEST_EQUALS( static_cast<int>(autoCapital), capital, TEST_LOCATION );
+
+ int action = 0;
+ DALI_TEST_CHECK( map[ "BUTTON_ACTION" ].Get( action ) );
+ DALI_TEST_EQUALS( static_cast<int>(buttonAction), action, TEST_LOCATION );
+
+ int variation = 0;
+ DALI_TEST_CHECK( map[ "VARIATION" ].Get( variation ) );
+ DALI_TEST_EQUALS( inputVariation, variation, TEST_LOCATION );
+
application.SendNotification();
application.Render();
END_TEST;
}
+int utcDaliTextEditorGetHeightForWidthChangeLineCountWhenTextChanged(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" utcDaliTextEditorGetHeightForWidthChangeLineCountWhenTextChanged ");
+
+ int lineCountBefore =0 ;
+ int lineCountAfter =0 ;
+
+ // Create a text editor
+ TextEditor textEditor = TextEditor::New();
+ //Set very large font-size using point-size
+ textEditor.SetProperty( TextEditor::Property::POINT_SIZE, 10) ;
+ //Specify font-family
+ textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+ //Specify size
+ textEditor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 100.f ) );
+ //Set text longer than width of textEditor
+ textEditor.SetProperty( TextEditor::Property::TEXT, "Short text");
+ //Set line wrap mode Character
+ textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, "CHARACTER");
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+
+
+ lineCountBefore = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+ textEditor.SetProperty( TextEditor::Property::TEXT, "This is very loooooooooooooooooooooooooooooooooooong text for test");
+ lineCountAfter = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+ // When the text changed, the Line-count should be updated according to new text.
+ // Because the GetHeightForWidth is called in Controller::GetLineCount(float width)
+ DALI_TEST_EQUALS( lineCountBefore ,1, TEST_LOCATION );
+ DALI_TEST_GREATER( lineCountAfter,1, TEST_LOCATION );
+
+
+ END_TEST;
+}
+
+
int utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountScrollingCase(void)
{
ToolkitTestApplication application;
DALI_TEST_EQUALS( lineCountAfter , lineCountBefore, TEST_LOCATION );
END_TEST;
+}
+
+int UtcDaliTextEditorAtlasLimitationIsEnabledForLargeFontPointSize(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextEditorAtlasLimitationIsEnabledForLargeFontPointSize ");
+
+ // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+ const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+ const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+ // Create a text editor
+ TextEditor textEditor = TextEditor::New();
+
+ //Set size to avoid automatic eliding
+ textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ //Set very large font-size using point-size
+ textEditor.SetProperty( TextEditor::Property::POINT_SIZE, 1000) ;
+ //Specify font-family
+ textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+ //Set text to check if appear or not
+ textEditor.SetProperty( TextEditor::Property::TEXT, "A");
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+ //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+ Vector3 naturalSize = textEditor.GetNaturalSize();
+
+ DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+ DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliTextEditorAtlasLimitationIsEnabledPerformanceCases(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextEditorAtlasLimitationIsEnabledPerformanceCases ");
+
+ // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+ const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+ const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+ Vector3 naturalSize; //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+ // Create a text editor
+ TextEditor textEditor = TextEditor::New();
+ //Set size to avoid automatic eliding
+ textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+ textEditor.SetProperty( TextEditor::Property::TEXT, "A");
+
+ const int numberOfCases = 6;
+ int arrayCases[numberOfCases] = {323, 326, 330, 600, 1630, 2500};
+
+ for (int index=0; index < numberOfCases; index++)
+ {
+ tet_printf(" UtcDaliTextEditorAtlasLimitationIsEnabledPerformanceCases point-size= %d \n", arrayCases[index]);
+ textEditor.SetProperty( TextEditor::Property::POINT_SIZE, arrayCases[index]) ;
+ application.GetScene().Add( textEditor );
+ application.SendNotification();
+ application.Render();
+ naturalSize = textEditor.GetNaturalSize();
+ DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+ DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+ }
+
+ END_TEST;
+}
+
+int UtcDaliTextEditorHyphenWrapMode(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextEditorHyphenWrapMode ");
+
+ int lineCount =0;
+ TextEditor textEditor = TextEditor::New();
+
+ textEditor.SetProperty( Actor::Property::SIZE, Vector2( 150.0f, 300.f ) );
+
+ application.GetScene().Add( textEditor );
+ application.SendNotification();
+ application.Render();
+
+ textEditor.SetProperty( TextEditor::Property::TEXT, "Hi Experimen" );
+ textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, DevelText::LineWrap::HYPHENATION);
+ DALI_TEST_EQUALS( textEditor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::HYPHENATION ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi Exp-
+ erimen
+ */
+ DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+ textEditor.SetProperty( TextEditor::Property::TEXT, "Hi Experimen" );
+ textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, DevelText::LineWrap::MIXED);
+ DALI_TEST_EQUALS( textEditor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::MIXED ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi
+ Experi-
+ men
+ */
+ DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+ END_TEST;
}
\ No newline at end of file
application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 100);
application.SendNotification();
application.Render();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 700);
application.SendNotification();
field.SetKeyInputFocus();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 1300);
application.SendNotification();
field.SetKeyInputFocus();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 1900);
application.SendNotification();
field.SetKeyInputFocus();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 2500);
application.SendNotification();
field.SetKeyInputFocus();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 3100);
application.SendNotification();
application.Render();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 3700);
application.SendNotification();
application.Render();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 4300);
application.SendNotification();
application.Render();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 4900);
application.SendNotification();
application.Render();
gAnchorClickedCallBackCalled = false;
// Create a tap event to touch the text field.
- TestGenerateTap(application, 30.0f, 25.0f);
+ TestGenerateTap(application, 30.0f, 25.0f, 5500);
application.SendNotification();
application.Render();
DALI_TEST_CHECK( !inputStyleChangedSignal );
// Create a tap event to touch the text field.
- TestGenerateTap( application, 63.0f, 25.0f, 300 );
+ TestGenerateTap( application, 63.0f, 25.0f, 700 );
// Render and notify
application.SendNotification();
DALI_TEST_EQUALS( field.GetProperty( TextField::Property::TEXT ).Get<std::string>(), "123456789", TEST_LOCATION );
END_TEST;
+}
+
+
+
+int UtcDaliTextFieldAtlasLimitationIsEnabledForLargeFontPointSize(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextFieldAtlasLimitationIsEnabledForLargeFontPointSize ");
+
+ // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+ const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+ const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+ // Create a text field
+ TextField textField = TextField::New();
+
+ //Set size to avoid automatic eliding
+ textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ //Set very large font-size using point-size
+ textField.SetProperty( TextField::Property::POINT_SIZE, 1000) ;
+ //Specify font-family
+ textField.SetProperty( TextField::Property::FONT_FAMILY, "DejaVu Sans");
+ //Set text to check if appear or not
+ textField.SetProperty( TextField::Property::TEXT, "A");
+
+ application.GetScene().Add( textField );
+
+ application.SendNotification();
+ application.Render();
+ //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+ Vector3 naturalSize = textField.GetNaturalSize();
+
+ DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+ DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliTextFieldAtlasLimitationIsEnabledPerformanceCases(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextFieldAtlasLimitationIsEnabledPerformanceCases ");
+
+ // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+ const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+ const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+ Vector3 naturalSize; //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+ // Create a text editor
+ TextField textField = TextField::New();
+
+ //Set size to avoid automatic eliding
+ textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ textField.SetProperty( TextField::Property::FONT_FAMILY, "DejaVu Sans");
+ textField.SetProperty( TextField::Property::TEXT, "A");
+
+ const int numberOfCases = 6;
+ int arrayCases[numberOfCases] = {323, 326, 330, 600, 1630, 2500};
+
+ for (int index=0; index < numberOfCases; index++)
+ {
+ tet_printf(" UtcDaliTextFieldAtlasLimitationIsEnabledPerformanceCases point-size= %d \n", arrayCases[index]);
+ textField.SetProperty( TextField::Property::POINT_SIZE, arrayCases[index]) ;
+ application.GetScene().Add( textField );
+ application.SendNotification();
+ application.Render();
+ naturalSize = textField.GetNaturalSize();
+ DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+ DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+ }
+
+ END_TEST;
}
\ No newline at end of file
END_TEST;
}
+
+int UtcDaliTextLabelAtlasLimitationIsEnabledForLargeFontPointSize(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextLabelAtlasLimitationIsEnabledForLargeFontPointSize ");
+
+ //TextLabel is not using Atlas but this is to unify font-size on text-controllers
+
+ // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+ const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+ const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+ // Create a text editor
+ TextLabel textLabel = TextLabel::New();
+ //Set size to avoid automatic eliding
+ textLabel.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+ //Set very large font-size using point-size
+ textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 1000);
+ //Specify font-family
+ textLabel.SetProperty( TextLabel::Property::FONT_FAMILY, "DejaVu Sans");
+ //Set text to check if appear or not
+ textLabel.SetProperty( TextLabel::Property::TEXT, "A");
+
+ application.GetScene().Add( textLabel );
+
+ application.SendNotification();
+ application.Render();
+ //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+ Vector3 naturalSize = textLabel.GetNaturalSize();
+
+ DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+ DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliTextLabelHyphenWrapMode(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextLabelHyphenWrapMode ");
+
+ int lineCount =0;
+ TextLabel label = TextLabel::New();
+ label.SetProperty( Actor::Property::SIZE, Vector2( 150.0f, 300.f ));
+ label.SetProperty( TextLabel::Property::POINT_SIZE, 12.f );
+ label.SetProperty( TextLabel::Property::MULTI_LINE, true);
+ application.GetScene().Add( label );
+ application.SendNotification();
+ application.Render();
+
+ label.SetProperty( TextLabel::Property::TEXT, "Hi Experimen" );
+ label.SetProperty(TextLabel::Property::LINE_WRAP_MODE,DevelText::LineWrap::HYPHENATION);
+ DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::HYPHENATION ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi Exp-
+ erimen
+ */
+ DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+ label.SetProperty( TextLabel::Property::TEXT, "Hi Experimen" );
+ label.SetProperty(TextLabel::Property::LINE_WRAP_MODE,DevelText::LineWrap::MIXED);
+ DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::MIXED ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi
+ Experi-
+ men
+ */
+ DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int utcDaliTextLabelGetHeightForWidthChangeLineCountWhenTextChanged(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" utcDaliTextLabelGetHeightForWidthChangeLineCountWhenTextChanged ");
+
+ int lineCountBefore =0 ;
+ int lineCountAfter =0 ;
+
+ // Create a text editor
+ TextLabel textLabel = TextLabel::New();
+ //Set very large font-size using point-size
+ textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 10) ;
+ //Specify font-family
+ textLabel.SetProperty( TextLabel::Property::FONT_FAMILY, "DejaVu Sans");
+ //Specify size
+ textLabel.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 100.f ) );
+ //Set text longer than width of textLabel
+ textLabel.SetProperty( TextLabel::Property::TEXT, "Short text");
+ //Set line wrap mode Character
+ textLabel.SetProperty(TextLabel::Property::LINE_WRAP_MODE, "CHARACTER");
+ textLabel.SetProperty(TextLabel::Property::MULTI_LINE, true);
+
+ application.GetScene().Add( textLabel );
+
+ application.SendNotification();
+ application.Render();
+
+
+ lineCountBefore = textLabel.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+
+ textLabel.SetProperty( TextLabel::Property::TEXT, "This is very loooooooooooooooooooooooooooooooooooong text for test");
+ lineCountAfter = textLabel.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+
+ // When the text changed, the Line-count should be updated according to new text.
+ // Because the GetHeightForWidth is called in Controller::GetLineCount(float width)
+ DALI_TEST_EQUALS( lineCountBefore ,1, TEST_LOCATION );
+ DALI_TEST_GREATER( lineCountAfter,1, TEST_LOCATION );
+
+
+ END_TEST;
+}
\ No newline at end of file
END_TEST;
}
+int UtcDaliVideoViewCustomShaderForCoverage3(void)
+{
+ ToolkitTestApplication application;
+ VideoView videoView = VideoView::New();
+ DALI_TEST_CHECK( videoView );
+
+ ToolkitApplication::DECODED_IMAGES_SUPPORTED = true;
+
+ videoView.SetProperty( Toolkit::VideoView::Property::UNDERLAY, false );
+ bool isUnderlay = videoView.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+ DALI_TEST_CHECK( !isUnderlay );
+
+ application.GetScene().Add( videoView );
+ videoView.SetProperty( VideoView::Property::VIDEO, "testvideo" );
+
+ Property::Map customShader;
+ customShader.Insert( "vertexShader", VERTEX_SHADER );
+
+ Property::Map map;
+ map.Insert( "shader", customShader );
+
+ videoView.SetProperty( VideoView::Property::VIDEO, map );
+
+ Property::Map map2;
+ Property::Value value = videoView.GetProperty( VideoView::Property::VIDEO );
+
+ DALI_TEST_CHECK( !value.Get( map2 ) );
+ END_TEST;
+}
+
int UtcDaliVideoViewPropertyUnderlay(void)
{
ToolkitTestApplication application;
propertyMap.Insert(Visual::Property::MIX_COLOR, Color::BLUE);
propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS, 10.0f );
propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS_POLICY, Toolkit::Visual::Transform::Policy::RELATIVE );
+ propertyMap.Insert( DevelVisual::Property::BORDERLINE_WIDTH, 20.0f );
+ propertyMap.Insert( DevelVisual::Property::BORDERLINE_COLOR, Color::RED );
+ propertyMap.Insert( DevelVisual::Property::BORDERLINE_OFFSET, -1.0f );
propertyMap.Insert( DevelColorVisual::Property::BLUR_RADIUS, 20.0f );
Visual::Base colorVisual = factory.CreateVisual( propertyMap );
DALI_TEST_CHECK( cornerRadiusPolicyValue );
DALI_TEST_CHECK( cornerRadiusPolicyValue->Get< int >() == Toolkit::Visual::Transform::Policy::RELATIVE );
+ Property::Value* borderlineWidthValue = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+ DALI_TEST_CHECK( borderlineWidthValue );
+ DALI_TEST_CHECK( borderlineWidthValue->Get< float >() == 20.0f );
+
+ Property::Value* borderlineColorValue = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+ DALI_TEST_CHECK( borderlineColorValue );
+ DALI_TEST_CHECK( borderlineColorValue->Get< Vector4 >() == Color::RED );
+
+ Property::Value* borderlineOffsetValue = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+ DALI_TEST_CHECK( borderlineOffsetValue );
+ DALI_TEST_CHECK( borderlineOffsetValue->Get< float >() == -1.0f );
+
Property::Value* blurRadiusValue = resultMap.Find( DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT );
DALI_TEST_CHECK( blurRadiusValue );
DALI_TEST_CHECK( blurRadiusValue->Get< float >() == 20.0f );
DALI_TEST_CHECK( colorValue );
DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::CYAN );
- colorValue = resultMap.Find( BorderVisual::Property::SIZE, Property::FLOAT );
+ sizeValue = resultMap.Find( BorderVisual::Property::SIZE, Property::FLOAT );
+ DALI_TEST_CHECK( sizeValue );
+ DALI_TEST_CHECK( sizeValue->Get<float>() == 10.f );
+
+ // Get default value of borderline values here
+
+ sizeValue = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+ DALI_TEST_CHECK( sizeValue );
+ DALI_TEST_CHECK( sizeValue->Get<float>() == 0.0f );
+
+ colorValue = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
DALI_TEST_CHECK( colorValue );
- DALI_TEST_CHECK( colorValue->Get<float>() == 10.f );
+ DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::BLACK );
+ sizeValue = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+ DALI_TEST_CHECK( sizeValue );
+ DALI_TEST_CHECK( sizeValue->Get<float>() == 0.0f );
END_TEST;
}
stopColors.PushBack( Color::GREEN );
propertyMap.Insert(GradientVisual::Property::STOP_COLOR, stopColors);
+ float borderlineWidth = 4.0f;
+ Vector4 cornerRadius(7.0f, 10.0f, 13.0f, 16.0f);
+ propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
+ propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, cornerRadius);
+
Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
Property::Map resultMap;
DALI_TEST_CHECK( value );
DALI_TEST_EQUALS( value->Get<Vector2>(), end , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), borderlineWidth , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::CORNER_RADIUS, Property::VECTOR4 );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<Vector4>(), cornerRadius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
value = resultMap.Find( GradientVisual::Property::STOP_OFFSET, Property::ARRAY );
DALI_TEST_CHECK( value );
Property::Array* offsetArray = value->GetArray();
stopColors.PushBack( Color::GREEN );
propertyMap.Insert(GradientVisual::Property::STOP_COLOR, stopColors);
+ float borderlineWidth = 8.0f;
+ Vector4 cornerRadius(1.0f, 2.0f, 4.0f, 8.0f);
+ propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
+ propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, cornerRadius);
+
Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
DALI_TEST_CHECK( gradientVisual );
DALI_TEST_CHECK( value );
DALI_TEST_EQUALS( value->Get<float>(), radius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+ value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<float>(), borderlineWidth , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+ value = resultMap.Find( DevelVisual::Property::CORNER_RADIUS, Property::VECTOR4 );
+ DALI_TEST_CHECK( value );
+ DALI_TEST_EQUALS( value->Get<Vector4>(), cornerRadius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
value = resultMap.Find( GradientVisual::Property::STOP_OFFSET, Property::ARRAY );
DALI_TEST_CHECK( value );
Property::Array* offsetArray = value->GetArray();
END_TEST;
}
-int UtcDaliColorVisualRenderIfTransparentProperty(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "Test the renderIfTransparent property of ColorVisual" );
-
- VisualFactory factory = VisualFactory::Get();
- Property::Map propertyMap;
- propertyMap.Insert( Visual::Property::TYPE, Visual::COLOR );
- propertyMap.Insert( ColorVisual::Property::MIX_COLOR, Color::BLUE );
-
- tet_infoline( "Check default value" );
- {
- Visual::Base testVisual = factory.CreateVisual( propertyMap );
- Property::Map returnedMap;
- testVisual.CreatePropertyMap( returnedMap );
-
- Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
- DALI_TEST_CHECK( renderIfTransparentProperty );
- DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
- }
-
- propertyMap.Insert( DevelColorVisual::Property::RENDER_IF_TRANSPARENT, true );
-
- tet_infoline( "Ensure set to value required" );
- {
- Visual::Base testVisual = factory.CreateVisual( propertyMap );
- Property::Map returnedMap;
- testVisual.CreatePropertyMap( returnedMap );
-
- Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
- DALI_TEST_CHECK( renderIfTransparentProperty );
- DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), true, TEST_LOCATION );
- }
-
- propertyMap[ DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = Color::BLUE;
-
- tet_infoline( "Ensure it returns default value if set to wrong type" );
- {
- Visual::Base testVisual = factory.CreateVisual( propertyMap );
- Property::Map returnedMap;
- testVisual.CreatePropertyMap( returnedMap );
-
- Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
- DALI_TEST_CHECK( renderIfTransparentProperty );
- DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
- }
-
- END_TEST;
-}
-
int UtcDaliSvgVisualCustomShader(void)
{
ToolkitTestApplication application;
END_TEST;
}
+int UtcDaliVisualBorderline(void)
+{
+#ifdef OLD_GRAPHICS_TEST
+ ToolkitTestApplication application;
+ tet_infoline( "UtcDaliVisualBorderline" );
+
+ static std::vector<UniformData> customUniforms =
+ {
+ UniformData("cornerRadius", Property::Type::VECTOR4),
+ UniformData("cornerRadiusPolicy", Property::Type::FLOAT),
+ UniformData("borderlineWidth", Property::Type::FLOAT),
+ UniformData("borderlineColor", Property::Type::VECTOR4),
+ UniformData("borderlineOffset", Property::Type::FLOAT),
+ };
+
+ TestGraphicsController& graphics = application.GetGraphicsController();
+ graphics.AddCustomUniforms(customUniforms);
+
+ // image visual
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ float cornerRadius = 5.0f;
+ float borderlineWidth = 30.0f;
+ Vector4 borderlineColor(1.0f, 0.0f, 0.0f, 1.0f);
+ float borderlineOffset = 1.0f;
+
+ properties[Visual::Property::TYPE] = Visual::IMAGE;
+ properties[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+ properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+ properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+ properties[DevelVisual::Property::BORDERLINE_COLOR] = borderlineColor;
+ properties[DevelVisual::Property::BORDERLINE_OFFSET] = borderlineOffset;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius) ), true, TEST_LOCATION );
+ // Default corner radius policy is absolute.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+ }
+
+ // color visual 1
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ Vector4 cornerRadius(23.0f, 2.0f, 3.0f, 2.3f);
+ float borderlineWidth = 30.0f;
+ Vector4 borderlineColor(0.5f, 0.4f, 0.3f, 0.2f);
+ float borderlineOffset = -0.4f;
+
+ properties[Visual::Property::TYPE] = Visual::COLOR;
+ properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+ properties["cornerRadius"] = cornerRadius;
+ properties["borderlineWidth"] = borderlineWidth;
+ properties["borderlineColor"] = borderlineColor;
+ properties["borderlineOffset"] = borderlineOffset;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+ }
+
+ // color visual 2, default color, default offset
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ float borderlineWidth = 30.0f;
+
+ properties[Visual::Property::TYPE] = Visual::COLOR;
+ properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+ properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ // Default borderline color is BLACK.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+ // Default borderline offset is 0.0f.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+ }
+
+ // color visual 3, offset not [-1.0 ~ 1.0], but uniform value is same anyway
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ float borderlineWidth = 30.0f;
+ Vector4 borderlineColor(0.5f, 0.4f, 0.3f, 0.2f);
+ float borderlineOffset = 37.4f;
+
+ properties[Visual::Property::TYPE] = Visual::COLOR;
+ properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+ properties["borderlineWidth"] = borderlineWidth;
+ properties["borderlineColor"] = borderlineColor;
+ properties["borderlineOffset"] = borderlineOffset;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+ // NOTE : borderlineOffset will clamp in fragment shader. not visual itself
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+ }
+
+ // gradient visual
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ float borderlineWidth = 30.0f;
+ float cornerRadius = 70.0f;
+
+ properties[Visual::Property::TYPE] = Visual::GRADIENT;
+ properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+ properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+ properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+ properties[GradientVisual::Property::START_POSITION] = Vector2( 0.5f, 0.5f );
+ properties[GradientVisual::Property::END_POSITION] = Vector2( -0.5f, -0.5f );
+ properties[GradientVisual::Property::UNITS] = GradientVisual::Units::USER_SPACE;
+
+ Property::Array stopOffsets;
+ stopOffsets.PushBack( 0.0f );
+ stopOffsets.PushBack( 0.6f );
+ stopOffsets.PushBack( 1.0f );
+ properties[GradientVisual::Property::STOP_OFFSET] = stopOffsets;
+
+ Property::Array stopColors;
+ stopColors.PushBack( Color::RED );
+ stopColors.PushBack( Color::YELLOW );
+ stopColors.PushBack( Color::GREEN );
+ properties[GradientVisual::Property::STOP_COLOR] = stopColors;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius) ), true, TEST_LOCATION );
+ // Default corner radius policy is absolute.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ // Default borderline color is BLACK.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+ // Default borderline offset is 0.0f.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+ }
+
+ // animated image visual
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ float borderlineWidth = 24.0f;
+ float borderlineOffset = -1.0f;
+
+ properties[Visual::Property::TYPE] = Visual::ANIMATED_IMAGE;
+ properties[ImageVisual::Property::URL] = TEST_GIF_FILE_NAME;
+ properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth + 10.0f; // Dummy Input
+ properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+ properties["borderlineOffset"] = borderlineOffset;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ // Default borderline color is BLACK.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+ }
+
+ // vector image visual
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ Vector4 cornerRadius(54.0f, 43.0f, 32.0f, 21.0f);
+ float borderlineWidth = 27.0f;
+ Vector4 borderlineColor(0.5f, 0.5f, 0.5f, 0.0f);
+
+ properties[Visual::Property::TYPE] = Visual::SVG;
+ properties[ImageVisual::Property::URL] = TEST_SVG_FILE_NAME;
+ properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+ properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+ properties[DevelVisual::Property::BORDERLINE_COLOR] = borderlineColor;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+ // Default corner radius policy is absolute.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+ // Default borderline offset is 0.0.
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+ }
+
+ // animated vector image visual
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ Vector4 cornerRadius(1.3f, 0.0f, 0.4f, 0.2f);
+ float borderlineWidth = 13.0f;
+ Vector4 borderlineColor(0.3f, 0.3f, 0.3f, 1.0f);
+ float borderlineOffset = 13.0f;
+
+ properties[Visual::Property::TYPE] = DevelVisual::ANIMATED_VECTOR_IMAGE;
+ properties[ImageVisual::Property::URL] = TEST_VECTOR_IMAGE_FILE_NAME;
+ properties["cornerRadius"] = cornerRadius;
+ properties[DevelVisual::Property::CORNER_RADIUS_POLICY] = Toolkit::Visual::Transform::Policy::RELATIVE;
+ properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+ properties["borderlineColor"] = borderlineColor;
+ properties[DevelVisual::Property::BORDERLINE_OFFSET] = borderlineOffset;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ application.GetScene().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::RELATIVE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+ }
+#else
+ tet_result(TET_PASS);
+#endif
+
+ END_TEST;
+}
+
+
int UtcDaliColorVisualBlurRadius(void)
{
ToolkitTestApplication application;
UniformData("size", Property::Type::VECTOR2),
UniformData("cornerRadius", Property::Type::VECTOR4),
UniformData("blurRadius", Property::Type::FLOAT),
+ UniformData("borderlineWidth", Property::Type::FLOAT),
+ UniformData("borderlineColor", Property::Type::VECTOR4),
+ UniformData("borderlineOffset", Property::Type::FLOAT),
};
TestGraphicsController& graphics = application.GetGraphicsController();
propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, Vector4(10.0f, 0.0f, 2.0f, 4.0f));
propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS_POLICY, Toolkit::Visual::Transform::Policy::RELATIVE);
propertyMap.Insert(DevelColorVisual::Property::BLUR_RADIUS, 20.0f);
+ propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 20.0f);
+ propertyMap.Insert(DevelVisual::Property::BORDERLINE_COLOR, Color::RED);
+ propertyMap.Insert(DevelVisual::Property::BORDERLINE_OFFSET, 1.0f);
Visual::Base colorVisual = factory.CreateVisual(propertyMap);
DummyControl dummyControl = DummyControl::New(true);
float targetOpacity = 0.5f;
Vector4 targetCornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
float targetBlurRadius = 10.0f;
+ float targetBorderlineWidth = 25.0f;
+ Vector4 targetBorderlineColor(1.0f, 1.0f, 1.0f, 1.0f);
+ float targetBorderlineOffset = -1.0f;
Animation animation = Animation::New(1.0f);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::MIX_COLOR), targetColor);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Transform::Property::SIZE), targetSize);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::CORNER_RADIUS), targetCornerRadius);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelColorVisual::Property::BLUR_RADIUS), targetBlurRadius);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), targetBorderlineWidth);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_COLOR), targetBorderlineColor);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_OFFSET), targetBorderlineOffset);
animation.Play();
application.SendNotification();
DALI_TEST_CHECK(blurRadiusValue);
DALI_TEST_EQUALS(blurRadiusValue->Get< float >(), targetBlurRadius, TEST_LOCATION);
+ Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+ DALI_TEST_CHECK(borderlineWidthValue);
+ DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+ Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+ DALI_TEST_CHECK(borderlineColorValue);
+ DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+ Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+ DALI_TEST_CHECK(borderlineOffsetValue);
+ DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
// Test uniform values
DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", targetColor), true, TEST_LOCATION);
DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector2>("offset", targetOffset), true, TEST_LOCATION);
DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector2>("size", targetSize), true, TEST_LOCATION);
DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("cornerRadius", targetCornerRadius), true, TEST_LOCATION);
DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("blurRadius", targetBlurRadius), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineWidth", targetBorderlineWidth), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("borderlineColor", targetBorderlineColor), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineOffset", targetBorderlineOffset), true, TEST_LOCATION);
// Test not-supported property
Property property1 = DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::PREMULTIPLIED_ALPHA);
DALI_TEST_CHECK(!property1.object);
DALI_TEST_CHECK(property1.propertyIndex == Property::INVALID_INDEX);
- // Test not-supported property
- Property property2 = DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelColorVisual::Property::RENDER_IF_TRANSPARENT);
- DALI_TEST_CHECK(!property2.object);
- DALI_TEST_CHECK(property2.propertyIndex == Property::INVALID_INDEX);
-
// Test unregistered visual
Property property3 = DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL2, Visual::Property::MIX_COLOR);
DALI_TEST_CHECK(!property3.object);
UniformData("offset", Property::Type::VECTOR2),
UniformData("size", Property::Type::VECTOR2),
UniformData("cornerRadius", Property::Type::VECTOR4),
+ UniformData("borderlineWidth", Property::Type::FLOAT),
+ UniformData("borderlineCOlor", Property::Type::VECTOR4),
+ UniformData("borderlineOffset", Property::Type::FLOAT),
UniformData("blurRadius", Property::Type::FLOAT),
};
Vector2 targetSize(1.1f, 1.1f);
float targetOpacity = 0.5f;
Vector4 targetCornerRadius(20.0f, 0.0f, 20.0f, 0.0f);
+ float targetBorderlineWidth = 77.7f;
+ Vector4 targetBorderlineColor(0.4f, 0.2f, 0.3f, 0.9f);
+ float targetBorderlineOffset = 1.0f;
float targetBlurRadius = 10.0f;
// Should work when the properties are not set before
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "offset"), targetOffset);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "size"), targetSize);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "cornerRadius"), targetCornerRadius);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineWidth"), targetBorderlineWidth);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineColor"), targetBorderlineColor);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineOffset"), targetBorderlineOffset);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "blurRadius"), targetBlurRadius);
animation.Play();
DALI_TEST_CHECK(cornerRadiusValue);
DALI_TEST_EQUALS(cornerRadiusValue->Get< Vector4 >(), targetCornerRadius, TEST_LOCATION);
+ Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+ DALI_TEST_CHECK(borderlineWidthValue);
+ DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+ Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+ DALI_TEST_CHECK(borderlineColorValue);
+ DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+ Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+ DALI_TEST_CHECK(borderlineOffsetValue);
+ DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
Property::Value* blurRadiusValue = resultMap.Find(DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT);
DALI_TEST_CHECK(blurRadiusValue);
DALI_TEST_EQUALS(blurRadiusValue->Get< float >(), targetBlurRadius, TEST_LOCATION);
{
#ifdef OLD_GRAPHICS_TEST
ToolkitTestApplication application;
- tet_infoline( "UtcDaliVisualGetVisualProperty01: Test animatable property, ImageVisual" );
+ tet_infoline( "UtcDaliVisualGetVisualProperty03: Test animatable property, ImageVisual" );
static std::vector<UniformData> customUniforms =
{
UniformData("cornerRadius", Property::Type::VECTOR4),
+ UniformData("borderlineWidth", Property::Type::FLOAT),
+ UniformData("borderlineColor", Property::Type::VECTOR4),
+ UniformData("borderlineOffset", Property::Type::FLOAT),
};
TestGraphicsController& graphics = application.GetGraphicsController();
Property::Map propertyMap;
propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+ //We must set some value because application cannot notify shader changed
+ propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, 1.0f);
+ propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 1.0f);
+
Visual::Base imageVisual = factory.CreateVisual(propertyMap);
DummyControl dummyControl = DummyControl::New(true);
float targetOpacity = 0.5f;
Vector4 targetCornerRadius(20.0f, 20.0f, 0.0f, 0.0f);
+ float targetBorderlineWidth = 10.0f;
+ Vector4 targetBorderlineColor(1.0f, 0.0f, 1.0f, 0.5f);
+ float targetBorderlineOffset = -1.5f;
Animation animation = Animation::New(1.0f);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::OPACITY), targetOpacity);
animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::CORNER_RADIUS), targetCornerRadius);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), targetBorderlineWidth);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_COLOR), targetBorderlineColor);
+ animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_OFFSET), targetBorderlineOffset);
animation.Play();
application.SendNotification();
DALI_TEST_CHECK(cornerRadiusValue);
DALI_TEST_EQUALS(cornerRadiusValue->Get< Vector4 >(), targetCornerRadius, TEST_LOCATION);
+ Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+ DALI_TEST_CHECK(borderlineWidthValue);
+ DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+ Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+ DALI_TEST_CHECK(borderlineColorValue);
+ DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+ Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+ DALI_TEST_CHECK(borderlineOffsetValue);
+ DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
// Test uniform value
DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("cornerRadius", targetCornerRadius), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineWidth", targetBorderlineWidth), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("borderlineColor", targetBorderlineColor), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineOffset", targetBorderlineOffset), true, TEST_LOCATION);
#else
tet_result(TET_PASS);
#endif
static std::shared_ptr<Dali::WebEngineRequestInterceptor> gRequestInterceptorInstance = nullptr;
static int gConsoleMessageCallbackCalled = 0;
static std::shared_ptr<Dali::WebEngineConsoleMessage> gConsoleMessageInstance = nullptr;
-static int gPolicyDecisionCallbackCalled = 0;
-static std::shared_ptr<Dali::WebEnginePolicyDecision> gPolicyDecisionInstance = nullptr;
+static int gResponsePolicyDecidedCallbackCalled = 0;
+static std::shared_ptr<Dali::WebEnginePolicyDecision> gResponsePolicyDecisionInstance = nullptr;
static int gCertificateConfirmCallbackCalled = 0;
static std::shared_ptr<Dali::WebEngineCertificate> gCertificateConfirmInstance = nullptr;
static int gSslCertificateChangedCallbackCalled = 0;
gScrollEdgeReachedCallbackCalled++;
}
-static void OnPolicyDecisionRequest(WebView view, std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
+static void OnResponsePolicyDecided(WebView view, std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
{
- gPolicyDecisionCallbackCalled++;
- gPolicyDecisionInstance = std::move(decision);
+ gResponsePolicyDecidedCallbackCalled++;
+ gResponsePolicyDecisionInstance = std::move(decision);
}
static void OnUrlChanged( WebView view, const std::string& url )
view.GetProperty( WebView::Property::TITLE ).Get( output );
DALI_TEST_EQUALS( output, testValue, TEST_LOCATION );
- // Check default value of favicon
- Dali::Toolkit::ImageView* favicon = &view.GetFavicon();
+ // Check the case that favicon is not null.
+ Dali::Toolkit::ImageView favicon = view.GetFavicon();
DALI_TEST_CHECK( favicon );
- Dali::Vector3 iconsize = favicon->GetProperty< Vector3 >( Dali::Actor::Property::SIZE );
+ Dali::Vector3 iconsize = favicon.GetProperty< Vector3 >( Dali::Actor::Property::SIZE );
DALI_TEST_CHECK( ( int )iconsize.width == 2 && ( int )iconsize.height == 2 );
+ // Check the case that favicon is null.
+ favicon = view.GetFavicon();
+ DALI_TEST_CHECK( !favicon );
+
END_TEST;
}
END_TEST;
}
-int UtcDaliWebViewPolicyDecisionRequest(void)
+int UtcDaliWebViewResponsePolicyDecisionRequest(void)
{
ToolkitTestApplication application;
// load url.
ConnectionTracker* testTracker = new ConnectionTracker();
- view.PolicyDecisionSignal().Connect( &OnPolicyDecisionRequest );
+ view.ResponsePolicyDecisionSignal().Connect( &OnResponsePolicyDecided );
bool signal1 = false;
- view.ConnectSignal( testTracker, "policyDecision", CallbackFunctor(&signal1) );
- DALI_TEST_EQUALS( gPolicyDecisionCallbackCalled, 0, TEST_LOCATION );
- DALI_TEST_CHECK(gPolicyDecisionInstance == 0);
+ view.ConnectSignal( testTracker, "responsePolicyDecided", CallbackFunctor(&signal1) );
+ DALI_TEST_EQUALS( gResponsePolicyDecidedCallbackCalled, 0, TEST_LOCATION );
+ DALI_TEST_CHECK(gResponsePolicyDecisionInstance == 0);
view.LoadUrl( TEST_URL1 );
Test::EmitGlobalTimerSignal();
- DALI_TEST_EQUALS( gPolicyDecisionCallbackCalled, 1, TEST_LOCATION );
+ DALI_TEST_EQUALS( gResponsePolicyDecidedCallbackCalled, 1, TEST_LOCATION );
DALI_TEST_CHECK( signal1 );
- // check policy decision & its frame.
- DALI_TEST_CHECK(gPolicyDecisionInstance != 0);
+ // check response policy decision & its frame.
+ DALI_TEST_CHECK(gResponsePolicyDecisionInstance != 0);
std::string testUrl("http://test.html");
- DALI_TEST_EQUALS(gPolicyDecisionInstance->GetUrl(), testUrl, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetUrl(), testUrl, TEST_LOCATION);
std::string testCookie("test:abc");
- DALI_TEST_EQUALS(gPolicyDecisionInstance->GetCookie(), testCookie, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetCookie(), testCookie, TEST_LOCATION);
Dali::WebEnginePolicyDecision::DecisionType testDecisionType = Dali::WebEnginePolicyDecision::DecisionType::USE;
- DALI_TEST_EQUALS(gPolicyDecisionInstance->GetDecisionType(), testDecisionType, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetDecisionType(), testDecisionType, TEST_LOCATION);
std::string testResponseMime("txt/xml");
- DALI_TEST_EQUALS(gPolicyDecisionInstance->GetResponseMime(), testResponseMime, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetResponseMime(), testResponseMime, TEST_LOCATION);
int32_t ResponseStatusCode = 500;
- DALI_TEST_EQUALS(gPolicyDecisionInstance->GetResponseStatusCode(), ResponseStatusCode, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetResponseStatusCode(), ResponseStatusCode, TEST_LOCATION);
Dali::WebEnginePolicyDecision::NavigationType testNavigationType = Dali::WebEnginePolicyDecision::NavigationType::LINK_CLICKED;
- DALI_TEST_EQUALS(gPolicyDecisionInstance->GetNavigationType(), testNavigationType, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetNavigationType(), testNavigationType, TEST_LOCATION);
std::string testScheme("test");
- DALI_TEST_EQUALS(gPolicyDecisionInstance->GetScheme(), testScheme, TEST_LOCATION);
- DALI_TEST_CHECK(gPolicyDecisionInstance->Use());
- DALI_TEST_CHECK(gPolicyDecisionInstance->Ignore());
- DALI_TEST_CHECK(gPolicyDecisionInstance->Suspend());
+ DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetScheme(), testScheme, TEST_LOCATION);
+ DALI_TEST_CHECK(gResponsePolicyDecisionInstance->Use());
+ DALI_TEST_CHECK(gResponsePolicyDecisionInstance->Ignore());
+ DALI_TEST_CHECK(gResponsePolicyDecisionInstance->Suspend());
- Dali::WebEngineFrame* webFrame = &(gPolicyDecisionInstance->GetFrame());
+ Dali::WebEngineFrame* webFrame = &(gResponsePolicyDecisionInstance->GetFrame());
DALI_TEST_CHECK(webFrame);
DALI_TEST_CHECK(webFrame->IsMainFrame());
- gPolicyDecisionInstance = nullptr;
+ gResponsePolicyDecisionInstance = nullptr;
END_TEST;
}
SET(SHADER_GENERATOR_NAME dali-shader-generator)
SET(SHADER_GENERATOR_SOURCES ${ROOT_SRC_DIR}/dali-toolkit/shader-generator/shader-generator.cpp)
+IF( WIN32)
+ # When Using VCPKG, the default is always set to Debug if CMAKE_BUILD_TYPE is not set
+ IF( NOT CMAKE_BUILD_TYPE )
+ SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/Debug/${SHADER_GENERATOR_NAME})
+ ELSE()
+ SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${SHADER_GENERATOR_NAME})
+ ENDIF()
+ELSE()
+ SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME})
+ENDIF()
+
IF(NOT ANDROID)
ADD_EXECUTABLE(${SHADER_GENERATOR_NAME} ${SHADER_GENERATOR_SOURCES})
- INSTALL(TARGETS ${SHADER_GENERATOR_NAME} DESTINATION ${BINDIR})
+ TARGET_LINK_LIBRARIES( ${SHADER_GENERATOR_NAME} ${COVERAGE} )
+ INSTALL(TARGETS ${SHADER_GENERATOR_NAME} RUNTIME DESTINATION bin)
ELSE()
# Need to build dali-shader-generator using the host compiler, not the android cross-compiler so
# that it can be run on the host machine
- OPTION(ANDROID_HOST_COMPILER "Provide the host compiler used by Android (Mandatory for Android")
+ OPTION(ANDROID_HOST_COMPILER "Provide the host compiler used by Android (Mandatory)")
IF(${ANDROID_HOST_COMPILER} STREQUAL "OFF")
MESSAGE(FATAL_ERROR "-DANDROID_HOST_COMPILER=\"Compiler\" must be set")
ENDIF()
SET(BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp")
ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP}
DEPENDS ${SHADER_GENERATOR_NAME}
- COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
+ COMMAND ${SHADER_GENERATOR_BINARY} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
SET(SOURCES ${SOURCES} ${BUILT_IN_SHADER_GEN_CPP})
add_definitions("-DDEBUG_ENABLED")
endif()
+ADD_DEFINITIONS( "-DBUILDING_DALI_SCENE_LOADER" )
+
foreach(flag ${PKGS_CFLAGS})
set(extra_flags "${extra_flags} ${flag}")
endforeach(flag)
"${GENERATED_SHADER_DIR}/generated/"
"${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h")
+IF( WIN32)
+ # When Using VCPKG, the default is always set to Debug if CMAKE_BUILD_TYPE is not set
+ IF( NOT CMAKE_BUILD_TYPE )
+ SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/../Debug/${SHADER_GENERATOR_NAME})
+ ELSE()
+ SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/../${CMAKE_BUILD_TYPE}/${SHADER_GENERATOR_NAME})
+ ENDIF()
+ELSE()
+ SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME})
+ENDIF()
+
SET( BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp")
ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP}
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME}
- COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
+ DEPENDS ${SHADER_GENERATOR_BINARY}
+ COMMAND ${SHADER_GENERATOR_BINARY} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
SET( scene_loader_src_files ${scene_loader_src_files} ${BUILT_IN_SHADER_GEN_CPP} )
}
case 0x8C3A: // GL_R11F_G11F_B10F
{
- format = Pixel::RGB32F;
+ format = Pixel::R11G11B10F;
break;
}
case 0x8D7C: // GL_RGBA8UI
: (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value) {
value = std::max(min[i], value);
}
- : [](const float* min, const float* max, uint32_t i, float& value) {
+ : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value) {
value = std::min(std::max(min[i], value), max[i]);
- });
+ }));
if(!clampFn)
{
s[Dali::Accessibility::State::HIGHLIGHTED] = GetCurrentlyHighlightedActor() == self;
s[Dali::Accessibility::State::ENABLED] = true;
s[Dali::Accessibility::State::SENSITIVE] = true;
- s[Dali::Accessibility::State::ANIMATED] = self.GetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED).Get<bool>();
s[Dali::Accessibility::State::VISIBLE] = true;
if(modal)
{
auto actor = Toolkit::ImageView::New(focusBorderImagePath);
actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
DevelControl::AppendAccessibilityAttribute(actor, "highlight", "");
- actor.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, true);
actor.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false);
return actor;
* @brief Set of accessibility attributes describing object in accessibility hierarchy
* @details Name "accessibilityAttributes", type Property::MAP
*/
- ACCESSIBILITY_ATTRIBUTES,
-
- /**
- * @brief Boolean flag describing object as animated
- * @details Name "accessibilityAnimated", type Property::BOOLEAN
- * @note Flag set to true will prevent BoundChanged accessibility signal from emiting
- */
- ACCESSIBILITY_ANIMATED
+ ACCESSIBILITY_ATTRIBUTES
};
} // namespace Property
* @details Name "grabHandleColor", type Property::VECTOR4.
*/
GRAB_HANDLE_COLOR,
+
+ /**
+ * @brief Enables the grab handle popup for text selection.
+ * @details Name "enableGrabHandlePopup", type Property::BOOLEAN.
+ * @note The default value is true, which means the grab handle popup is enabled by default.
+ */
+ ENABLE_GRAB_HANDLE_POPUP,
+
+ /**
+ * @brief The settings to relating to the System's Input Method, Key and Value.
+ * @details Name "inputMethodSettings", type Property::MAP.
+ *
+ * @note VARIATION key can be changed depending on PANEL_LAYOUT.
+ * For example, when PANEL_LAYOUT key is InputMethod::PanelLayout::NORMAL,
+ * then VARIATION would be among NORMAL, WITH_FILENAME, and WITH_PERSON_NAME in Dali::InputMethod::NormalLayout.
+ * For more information, see Dali::InputMethod::Category.
+ *
+ * Example Usage:
+ * @code
+ * Property::Map propertyMap;
+ * InputMethod::PanelLayout::Type panelLayout = InputMethod::PanelLayout::NUMBER;
+ * InputMethod::AutoCapital::Type autoCapital = InputMethod::AutoCapital::WORD;
+ * InputMethod::ButtonAction::Type buttonAction = InputMethod::ButtonAction::GO;
+ * int inputVariation = 1;
+ * propertyMap["PANEL_LAYOUT"] = panelLayout;
+ * propertyMap["AUTO_CAPITALIZE"] = autoCapital;
+ * propertyMap["BUTTON_ACTION"] = buttonAction;
+ * propertyMap["VARIATION"] = inputVariation;
+ *
+ * editor.SetProperty(DevelTextEditor::Property::INPUT_METHOD_SETTINGS, propertyMap);
+ * @endcode
+ */
+ INPUT_METHOD_SETTINGS,
};
} // namespace Property
return Dali::Toolkit::GetImpl(*this).GetBackForwardList();
}
-Dali::Toolkit::ImageView& WebView::GetFavicon()
+Dali::Toolkit::ImageView WebView::GetFavicon() const
{
return Dali::Toolkit::GetImpl(*this).GetFavicon();
}
return Dali::Toolkit::GetImpl(*this).ConsoleMessageSignal();
}
-WebView::WebViewPolicyDecisionSignalType& WebView::PolicyDecisionSignal()
+WebView::WebViewResponsePolicyDecisionSignalType& WebView::ResponsePolicyDecisionSignal()
{
- return Dali::Toolkit::GetImpl(*this).PolicyDecisionSignal();
+ return Dali::Toolkit::GetImpl(*this).ResponsePolicyDecisionSignal();
}
WebView::WebViewCertificateSignalType& WebView::CertificateConfirmSignal()
using WebViewConsoleMessageSignalType = Signal<void(WebView, std::shared_ptr<Dali::WebEngineConsoleMessage>)>;
/**
- * @brief WebView signal type related with policy decision.
+ * @brief WebView signal type related with response policy decision.
*/
- using WebViewPolicyDecisionSignalType = Signal<void(WebView, std::shared_ptr<Dali::WebEnginePolicyDecision>)>;
+ using WebViewResponsePolicyDecisionSignalType = Signal<void(WebView, std::shared_ptr<Dali::WebEnginePolicyDecision>)>;
/**
* @brief WebView signal type related with certificate changed.
Dali::Toolkit::WebBackForwardList* GetBackForwardList() const;
/**
- * @brief Get Favicon of web page.
+ * @brief Get favicon of web page.
*
- * @return Handle to a fav icon
+ * @return Handle to a favicon
*/
- Dali::Toolkit::ImageView& GetFavicon();
+ Dali::Toolkit::ImageView GetFavicon() const;
/**
* @brief Load a web page based on a given URL.
WebViewConsoleMessageSignalType& ConsoleMessageSignal();
/**
- * @brief Connect to this signal to be notified when new policy would be decided.
+ * @brief Connect to this signal to be notified when response policy would be decided.
*
* @return A signal object to connect with.
*/
- WebViewPolicyDecisionSignalType& PolicyDecisionSignal();
+ WebViewResponsePolicyDecisionSignalType& ResponsePolicyDecisionSignal();
/**
* @brief Connect to this signal to be notified when certificate need be confirmed.
${devel_api_src_dir}/controls/web-view/web-view.cpp
${devel_api_src_dir}/focus-manager/keyinput-focus-manager.cpp
${devel_api_src_dir}/focus-manager/keyboard-focus-manager-devel.cpp
+ ${devel_api_src_dir}/focus-manager/focus-finder.cpp
${devel_api_src_dir}/image-loader/async-image-loader-devel.cpp
${devel_api_src_dir}/image-loader/atlas-upload-observer.cpp
${devel_api_src_dir}/image-loader/image-atlas.cpp
SET( devel_api_focus_manager_header_files
${devel_api_src_dir}/focus-manager/keyinput-focus-manager.h
${devel_api_src_dir}/focus-manager/keyboard-focus-manager-devel.h
+ ${devel_api_src_dir}/focus-manager/focus-finder.h
)
SET( devel_api_image_loader_header_files
--- /dev/null
+/*\r
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// CLASS HEADER\r
+#include "focus-finder.h"\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/devel-api/common/singleton-service.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/internal/focus-manager/focus-finder-impl.h>\r
+\r
+namespace Dali\r
+{\r
+namespace Toolkit\r
+{\r
+FocusFinder::FocusFinder()\r
+{\r
+}\r
+\r
+FocusFinder::~FocusFinder()\r
+{\r
+}\r
+\r
+FocusFinder FocusFinder::Get()\r
+{\r
+ FocusFinder finder;\r
+\r
+ // Check whether the focus finder is already created\r
+ SingletonService singletonService(SingletonService::Get());\r
+ if(singletonService)\r
+ {\r
+ Dali::BaseHandle handle = singletonService.GetSingleton(typeid(FocusFinder));\r
+ if(handle)\r
+ {\r
+ // If so, downcast the handle of singleton to focus finder\r
+ finder = FocusFinder(dynamic_cast<Internal::FocusFinder*>(handle.GetObjectPtr()));\r
+ }\r
+\r
+ if(!finder)\r
+ {\r
+ // If not, create the focus finder and register it as a singleton\r
+ finder = FocusFinder(new Internal::FocusFinder());\r
+ singletonService.Register(typeid(finder), finder);\r
+ }\r
+ }\r
+\r
+ return finder;\r
+}\r
+\r
+FocusFinder::FocusFinder(Internal::FocusFinder* impl)\r
+: BaseHandle(impl)\r
+{\r
+}\r
+\r
+Actor FocusFinder::GetNearestFocusableActor(Actor focusedActor, Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+ return GetImpl(*this).GetNearestFocusableActor(focusedActor, direction);\r
+}\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
--- /dev/null
+#ifndef DALI_TOOLKIT_FOCUS_FINDER_H\r
+#define DALI_TOOLKIT_FOCUS_FINDER_H\r
+\r
+/*\r
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/public-api/controls/control.h>\r
+\r
+namespace Dali\r
+{\r
+namespace Toolkit\r
+{\r
+namespace Internal DALI_INTERNAL\r
+{\r
+class FocusFinder;\r
+}\r
+\r
+/**\r
+ * FocusFinder\r
+ * This class used for finding the next focusable actor in a given direction\r
+ * from a actor that currently has focus.\r
+ */\r
+class DALI_TOOLKIT_API FocusFinder : public BaseHandle\r
+{\r
+public:\r
+ /**\r
+ * Create a FocusFinder handle; this can be initialised with FocusFinder::Get()\r
+ * Calling member functions with an uninitialised handle is not allowed.\r
+ */\r
+ FocusFinder();\r
+\r
+ /**\r
+ * @brief Destructor\r
+ *\r
+ * This is non-virtual since derived Handle types must not contain data or virtual methods.\r
+ */\r
+ ~FocusFinder();\r
+\r
+ /**\r
+ * @brief Get the singleton of FocusFinder object.\r
+ * @return A handle to the FocusFinder control.\r
+ */\r
+ static FocusFinder Get();\r
+\r
+ /**\r
+ * Get the nearest focusable actor.\r
+ * @param [in] focusedActor The current focused actor.\r
+ * @param [in] direction The direction.\r
+ * @return The nearest focusable actor, or null if none exists.\r
+ */\r
+ Actor GetNearestFocusableActor(Actor focusedActor, Toolkit::Control::KeyboardFocus::Direction direction);\r
+\r
+private:\r
+ explicit DALI_INTERNAL FocusFinder(Internal::FocusFinder* impl);\r
+\r
+}; // class FocusFinder\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_FOCUS_FINDER_H\r
CENTER, ///< Items are positioned at the center of the container
FLEX_END, ///< Items are positioned at the end of the container
SPACE_BETWEEN, ///< Items are positioned with equal space between the items
- SPACE_AROUND ///< Items are positioned with equal space before, between, and after the items
+ SPACE_AROUND, ///< Items are positioned with equal space before, and after the items
+ SPACE_EVENLY ///< Items are positioned with equal space before, between, and after the items
};
/**
#define DALI_TOOLKIT_TEXT_ENUMERATIONS_DEVEL_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
};
} // namespace VerticalLineAlignment
+namespace LineWrap
+{
+enum Mode
+{
+ WORD,
+ CHARACTER,
+ HYPHENATION, // HYPHENATION mode will add hyphen and move part of the word to the next line.
+ MIXED // MIXEd mode will apply WORD mode, if failed try HYPHENATION mode, if failed try CHARACTER.
+};
+
+} // namespace LineWrap
} // namespace DevelText
MarkupProcessData markupProcessData(colorRuns,
fontDescriptionRuns,
textModel->mLogicalModel->mEmbeddedItems,
- textModel->mLogicalModel->mAnchors);
+ textModel->mLogicalModel->mAnchors,
+ textModel->mLogicalModel->mUnderlinedCharacterRuns);
if(textParameters.markupEnabled)
{
// Resize the vector of positions to have the same size than the vector of glyphs.
rendererParameters.positions.Resize(numberOfGlyphs);
- textModel->mLineWrapMode = LineWrap::WORD;
+ textModel->mLineWrapMode = Text::LineWrap::WORD;
textModel->mIgnoreSpacesAfterText = false;
textModel->mMatchSystemLanguageDirection = false;
Text::Layout::Parameters layoutParameters(internalDataModel.textLayoutArea,
/*
-* Copyright (c) 2020 Samsung Electronics Co., Ltd.
+* 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.
case Dali::Pixel::DEPTH_UNSIGNED_INT:
case Dali::Pixel::DEPTH_FLOAT:
case Dali::Pixel::DEPTH_STENCIL:
+ case Dali::Pixel::R11G11B10F:
{
DALI_LOG_ERROR("Pixel format not compatible.\n");
byteOffset = 0;
#define DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * 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.
MIX_COLOR = Toolkit::ColorVisual::Property::MIX_COLOR,
/**
- * @brief Whether to render if the MIX_COLOR is transparent.
- * @details Name "renderIfTransparent", type Property::BOOLEAN.
- * @note Optional.
- * @note By default it's false, i.e. ColorVisual will not render if the MIX_COLOR is transparent.
- */
- RENDER_IF_TRANSPARENT = MIX_COLOR + 1,
-
- /**
* @brief The blur radius of the visual.
* @details Name "blurRadius", type Property::FLOAT, animatable.
* If the value is 0, the edge is sharp. Otherwise, the larger the value, the more the edge is blurred.
* If it it RELATIVE, the corner radius value is relative to the smaller of the visual width and visual height.
*/
CORNER_RADIUS_POLICY = OPACITY + 3,
+
+ /**
+ * @brief The width for the borderline of the visual
+ * @details Name "borderlineWidth", type Property::FLOAT, animatable
+ * @note Optional. Default value is 0.0f.
+ */
+ BORDERLINE_WIDTH = OPACITY + 4,
+
+ /**
+ * @brief The color for the borderline of the visual
+ * @details Name "borderlineColor", type Property::VECTOR4, animatable
+ * @note Default value is Color::BLACK
+ */
+ BORDERLINE_COLOR = OPACITY + 5,
+
+ /**
+ * @brief The offset from the visual borderline (recommend [-1.0f to 1.0f]).
+ * @details Name "borderlineOffset", type Property::FLOAT, animatable
+ * @note Default value is 0.0f.
+ * @note This value will be clipped by [-1.0f to 1.0f].
+ */
+ BORDERLINE_OFFSET = OPACITY + 6,
};
} // namespace Property
const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityRole", Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityHighlightable", Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
-const PropertyRegistration Control::Impl::PROPERTY_22(typeRegistration, "accessibilityAnimated", Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
// clang-format on
Control::Impl::Impl(Control& controlImpl)
StopObservingVisual(iter->visual);
}
- AccessibilityDeregister(false);
// All gesture detectors will be destroyed so no need to disconnect.
delete mStartingPinchScale;
}
break;
}
-
- case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED:
- {
- bool animated;
- if(value.Get(animated))
- {
- controlImpl.mImpl->mAccessibilityAnimated = animated;
- }
- break;
- }
}
}
}
value = controlImpl.mImpl->mAccessibilityAttributes;
break;
}
-
- case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED:
- {
- value = controlImpl.mImpl->mAccessibilityAnimated;
- break;
- }
}
}
{
place->Get(value);
}
+ else
+ {
+ Dali::Accessibility::ReadingInfoTypes types;
+ types[Dali::Accessibility::ReadingInfoType::NAME] = true;
+ types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
+ types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
+ types[Dali::Accessibility::ReadingInfoType::STATE] = true;
+ return types;
+ }
if(value.empty())
{
return nullptr;
}
-void Control::Impl::PositionOrSizeChangedCallback(PropertyNotification& p)
-{
- auto self = Dali::Actor::DownCast(p.GetTarget());
- if(Dali::Accessibility::IsUp() && !self.GetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED).Get<bool>())
- {
- auto extents = DevelActor::CalculateScreenExtents(self);
- Dali::Accessibility::Accessible::Get(self)->EmitBoundsChanged(extents);
- }
-}
-
-void Control::Impl::CulledChangedCallback(PropertyNotification& p)
-{
- if(Dali::Accessibility::IsUp())
- {
- auto self = Dali::Actor::DownCast(p.GetTarget());
- Dali::Accessibility::Accessible::Get(self)->EmitShowing(!self.GetProperty(DevelActor::Property::CULLED).Get<bool>());
- }
-}
-
-void Control::Impl::AccessibilityRegister()
-{
- if(!accessibilityNotificationSet)
- {
- accessibilityNotificationPosition = mControlImpl.Self().AddPropertyNotification(Actor::Property::POSITION, StepCondition(0.01f));
- accessibilityNotificationPosition.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
- accessibilityNotificationPosition.NotifySignal().Connect(&Control::Impl::PositionOrSizeChangedCallback);
-
- accessibilityNotificationSize = mControlImpl.Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(0.01f));
- accessibilityNotificationSize.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
- accessibilityNotificationSize.NotifySignal().Connect(&Control::Impl::PositionOrSizeChangedCallback);
-
- accessibilityNotificationCulled = mControlImpl.Self().AddPropertyNotification(DevelActor::Property::CULLED, LessThanCondition(0.5f));
- accessibilityNotificationCulled.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
- accessibilityNotificationCulled.NotifySignal().Connect(&Control::Impl::CulledChangedCallback);
-
- accessibilityNotificationSet = true;
- }
-}
-
-void Control::Impl::AccessibilityDeregister(bool remove)
-{
- if(accessibilityNotificationSet)
- {
- accessibilityNotificationPosition.NotifySignal().Disconnect(&Control::Impl::PositionOrSizeChangedCallback);
- if(remove)
- {
- mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationPosition);
- }
- accessibilityNotificationPosition.Reset();
- accessibilityNotificationPosition = {};
-
- accessibilityNotificationSize.NotifySignal().Disconnect(&Control::Impl::PositionOrSizeChangedCallback);
- if(remove)
- {
- mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationSize);
- }
- accessibilityNotificationSize.Reset();
- accessibilityNotificationSize = {};
-
- accessibilityNotificationCulled.NotifySignal().Disconnect(&Control::Impl::CulledChangedCallback);
- if(remove)
- {
- mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationCulled);
- }
- accessibilityNotificationCulled.Reset();
- accessibilityNotificationCulled = {};
- accessibilityNotificationSet = false;
- }
-}
-
} // namespace Internal
} // namespace Toolkit
Dali::Accessibility::Role mAccessibilityRole = Dali::Accessibility::Role::UNKNOWN;
std::vector<std::vector<Accessibility::Address>> mAccessibilityRelations;
- bool mAccessibilityAnimated = false;
// Gesture Detection
PinchGestureDetector mPinchGestureDetector;
static Dali::Accessibility::Accessible* GetAccessibilityObject(Dali::Actor actor);
Dali::Accessibility::Accessible* GetAccessibilityObject();
- void AccessibilityRegister();
- void AccessibilityDeregister(bool remove);
-
std::function<std::unique_ptr<Dali::Accessibility::Accessible>(Actor)> accessibilityConstructor;
std::unique_ptr<Dali::Accessibility::Accessible> accessibilityObject;
- Dali::PropertyNotification accessibilityNotificationPosition, accessibilityNotificationSize, accessibilityNotificationCulled;
- bool accessibilityNotificationSet = false;
- static void PositionOrSizeChangedCallback(PropertyNotification&);
- static void CulledChangedCallback(PropertyNotification&);
};
} // namespace Internal
{"center", Toolkit::FlexContainer::JUSTIFY_CENTER},
{"flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END},
{"spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN},
- {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND}};
+ {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND},
+ {"spaceEvenly", Toolkit::FlexContainer::JUSTIFY_SPACE_EVENLY}};
const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof(JUSTIFY_CONTENT_STRING_TABLE) / sizeof(JUSTIFY_CONTENT_STRING_TABLE[0]);
const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "fontSizeScale", FLOAT, FONT_SIZE_SCALE )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "primaryCursorPosition", INTEGER, PRIMARY_CURSOR_POSITION )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "grabHandleColor", VECTOR4, GRAB_HANDLE_COLOR )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "enableGrabHandlePopup", BOOLEAN, ENABLE_GRAB_HANDLE_POPUP )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "inputMethodSettings", MAP, INPUT_METHOD_SETTINGS )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED)
impl.RequestTextRelayout();
break;
}
+ case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
+ {
+ const bool grabHandlePopupEnabled = value.Get<bool>();
+ DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_GRAB_HANDLE_POPUP %d\n", impl.mController.Get(), grabHandlePopupEnabled);
+
+ impl.mController->SetGrabHandlePopupEnabled(grabHandlePopupEnabled);
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::INPUT_METHOD_SETTINGS:
+ {
+ const Property::Map* map = value.GetMap();
+ if(map)
+ {
+ impl.mInputMethodOptions.ApplyProperty(*map);
+ }
+ impl.mController->SetInputModePassword(impl.mInputMethodOptions.IsPassword());
+
+ Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
+ if(control == textEditor)
+ {
+ impl.mInputMethodContext.ApplyOptions(impl.mInputMethodOptions);
+ }
+ break;
+ }
} // switch
} // texteditor
}
value = impl.mDecorator->GetHandleColor();
break;
}
+ case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
+ {
+ value = impl.mController->IsGrabHandlePopupEnabled();
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::INPUT_METHOD_SETTINGS:
+ {
+ Property::Map map;
+ impl.mInputMethodOptions.RetrieveProperty(map);
+ value = map;
+ break;
+ }
} //switch
}
ResizeActor(mActiveLayer, contentSize);
}
+ // If there is text changed, callback is called.
+ if(mTextChanged)
+ {
+ EmitTextChangedSignal();
+ }
+
const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
if((Text::Controller::NONE_UPDATED != updateTextType) ||
}
RenderText(updateTextType);
-
- // If there is text changed, callback is called.
- if(mTextChanged)
- {
- EmitTextChangedSignal();
- }
}
// The text-editor emits signals when the input style changes. These changes of style are
if(mInputMethodContext && IsEditable())
{
// All input panel properties, such as layout, return key type, and input hint, should be set before input panel activates (or shows).
+ mInputMethodContext.ApplyOptions(mInputMethodOptions);
mInputMethodContext.NotifyTextInputMultiLine(true);
mInputMethodContext.StatusChangedSignal().Connect(this, &TextEditor::KeyboardStatusChanged);
Dali::Toolkit::GetImpl(slf).getController()->CopyStringToClipboard(txt.substr(startPosition, endPosition - startPosition));
slf.SetProperty(Toolkit::TextEditor::Property::TEXT,
- txt.substr(0, startPosition) + txt.substr(endPosition - startPosition, txt.size()));
+ txt.substr(0, startPosition) + txt.substr(endPosition));
+
+ return true;
+}
+
+bool TextEditor::AccessibleImpl::DeleteText(size_t startPosition,
+ size_t endPosition)
+{
+ if(endPosition <= startPosition)
+ return false;
+
+ auto slf = Toolkit::TextEditor::DownCast(Self());
+ auto txt = slf.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
+
+ slf.SetProperty(Toolkit::TextEditor::Property::TEXT,
+ txt.substr(0, startPosition) + txt.substr(endPosition));
return true;
}
return states;
}
+bool TextEditor::AccessibleImpl::InsertText(size_t startPosition,
+ std::string text)
+{
+ auto slf = Toolkit::TextEditor::DownCast(Self());
+ auto txt = slf.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
+
+ txt.insert(startPosition, text);
+
+ slf.SetProperty(Toolkit::TextEditor::Property::TEXT, std::move(txt));
+
+ return true;
+}
+
+bool TextEditor::AccessibleImpl::SetTextContents(std::string newContents)
+{
+ auto slf = Toolkit::TextEditor::DownCast(Self());
+ slf.SetProperty(Toolkit::TextEditor::Property::TEXT, std::move(newContents));
+ return true;
+}
+
} // namespace Internal
} // namespace Toolkit
Dali::Animation mAnimation; ///< Scroll indicator Show/Hide Animation.
Dali::TimePeriod mAnimationPeriod;
std::vector<Actor> mClippingDecorationActors; ///< Decoration actors which need clipping.
+ Dali::InputMethodOptions mInputMethodOptions;
Actor mRenderableActor;
Actor mActiveLayer;
bool CopyText(size_t startPosition, size_t endPosition) override;
bool CutText(size_t startPosition, size_t endPosition) override;
Accessibility::States CalculateStates() override;
+ bool InsertText(size_t startPosition, std::string text) override;
+ bool SetTextContents(std::string newContents) override;
+ bool DeleteText(size_t startPosition, size_t endPosition) override;
};
};
ResizeActor(mActiveLayer, contentSize);
}
+ // If there is text changed, callback is called.
+ if(mTextChanged)
+ {
+ EmitTextChangedSignal();
+ }
+
const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
if((Text::Controller::NONE_UPDATED != updateTextType) ||
}
RenderText(updateTextType);
-
- // If there is text changed, callback is called.
- if(mTextChanged)
- {
- EmitTextChangedSignal();
- }
}
// The text-field emits signals when the input style changes. These changes of style are
Dali::Toolkit::GetImpl(slf).getController()->CopyStringToClipboard(txt.substr(startPosition, endPosition - startPosition));
slf.SetProperty(Toolkit::TextField::Property::TEXT,
- txt.substr(0, startPosition) + txt.substr(endPosition - startPosition, txt.size()));
+ txt.substr(0, startPosition) + txt.substr(endPosition));
+
+ return true;
+}
+
+bool TextField::AccessibleImpl::DeleteText(size_t startPosition,
+ size_t endPosition)
+{
+ if(endPosition <= startPosition)
+ return false;
+
+ auto slf = Toolkit::TextField::DownCast(Self());
+ auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+
+ slf.SetProperty(Toolkit::TextField::Property::TEXT,
+ txt.substr(0, startPosition) + txt.substr(endPosition));
return true;
}
return states;
}
+bool TextField::AccessibleImpl::InsertText(size_t startPosition,
+ std::string text)
+{
+ auto slf = Toolkit::TextField::DownCast(Self());
+ auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+
+ txt.insert(startPosition, text);
+
+ slf.SetProperty(Toolkit::TextField::Property::TEXT, std::move(txt));
+
+ return true;
+}
+
+bool TextField::AccessibleImpl::SetTextContents(std::string newContents)
+{
+ auto slf = Toolkit::TextField::DownCast(Self());
+ slf.SetProperty(Toolkit::TextField::Property::TEXT, std::move(newContents));
+ return true;
+}
+
} // namespace Internal
} // namespace Toolkit
bool CopyText(size_t startPosition, size_t endPosition) override;
bool CutText(size_t startPosition, size_t endPosition) override;
Accessibility::States CalculateStates() override;
+ bool InsertText(size_t startPosition, std::string text) override;
+ bool SetTextContents(std::string newContents) override;
+ bool DeleteText(size_t startPosition, size_t endPosition) override;
};
};
#include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/devel-api/common/stage.h>
padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
const Vector2& localPoint = gesture.GetLocalPoint();
mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top);
+
+ // parents can also listen for tap gesture events
+ Dali::DevelActor::SetNeedGesturePropagation(Self(), true);
}
void TextLabel::AnchorClicked(const std::string& href)
// EXTERNAL INCLUDES
#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/devel-api/rendering/texture-devel.h>
#include <dali/devel-api/scripting/scripting.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/adaptor-framework/native-image-source.h>
new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::VIDEO));
});
+ //Enable highightability
+ Self().SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
+
//update self property
self.RegisterProperty(IS_VIDEO_VIEW_PROPERTY_NAME, true, Property::READ_WRITE);
}
Dali::Shader VideoView::CreateShader()
{
- std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n";
+ std::string fragmentShader;
std::string vertexShader;
std::string customFragmentShader;
bool checkShader = false;
if(!fragmentShaderValue || !checkShader)
{
- fragmentShader += SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+ fragmentShader = SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+ DevelTexture::ApplyNativeFragmentShader(mNativeTexture, fragmentShader);
}
}
else
{
- vertexShader = SHADER_VIDEO_VIEW_TEXTURE_VERT.data();
- fragmentShader += SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+ vertexShader = SHADER_VIDEO_VIEW_TEXTURE_VERT.data();
+ fragmentShader = SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+ DevelTexture::ApplyNativeFragmentShader(mNativeTexture, fragmentShader);
}
return Dali::Shader::New(vertexShader, fragmentShader);
DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "frameRendered", FRAME_RENDERED_SIGNAL )
DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "requestInterceptor", REQUEST_INTERCEPTOR_SIGNAL )
DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "consoleMessage", CONSOLE_MESSAGE_SIGNAL )
-DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "policyDecision", POLICY_DECISION )
+DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "responsePolicyDecided", POLICY_DECISION )
DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "certificateConfirm", CERTIFICATE_CONFIRM_SIGNAL )
DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "sslCertificateChanged", SSL_CERTIFICATE_CHANGED_SIGNAL )
DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "httpAuthRequest", HTTP_AUTH_REQUEST_SIGNAL )
mWebEngine.FrameRenderedSignal().Connect(this, &WebView::OnFrameRendered);
mWebEngine.RequestInterceptorSignal().Connect(this, &WebView::OnInterceptRequest);
mWebEngine.ConsoleMessageSignal().Connect(this, &WebView::OnConsoleMessage);
- mWebEngine.PolicyDecisionSignal().Connect(this, &WebView::OnPolicyDecisionRequest);
+ mWebEngine.ResponsePolicyDecisionSignal().Connect(this, &WebView::OnResponsePolicyDecided);
mWebEngine.CertificateConfirmSignal().Connect(this, &WebView::OnCertificateConfirm);
mWebEngine.SslCertificateChangedSignal().Connect(this, &WebView::OnSslCertificateChanged);
mWebEngine.HttpAuthHandlerSignal().Connect(this, &WebView::OnHttpAuthenticationRequest);
return mWebBackForwardList.get();
}
-Dali::Toolkit::ImageView& WebView::GetFavicon()
+Dali::Toolkit::ImageView WebView::GetFavicon() const
{
+ Dali::Toolkit::ImageView faviconView;
if(mWebEngine)
{
Dali::PixelData pixelData = mWebEngine.GetFavicon();
- mFaviconView = CreateImageView(pixelData);
+ faviconView = CreateImageView(pixelData);
}
- return mFaviconView;
+ return faviconView;
}
void WebView::LoadUrl(const std::string& url)
}
}
-Dali::Toolkit::ImageView WebView::CreateImageView(Dali::PixelData pixel)
+Dali::Toolkit::ImageView WebView::CreateImageView(Dali::PixelData pixel) const
{
+ if(!pixel)
+ {
+ return Dali::Toolkit::ImageView();
+ }
+
std::string url = Dali::Toolkit::Image::GenerateUrl(pixel);
Dali::Toolkit::ImageView imageView = Dali::Toolkit::ImageView::New(url);
imageView.SetProperty(Dali::Actor::Property::SIZE, Vector2(pixel.GetWidth(), pixel.GetHeight()));
return mConsoleMessageSignal;
}
-Dali::Toolkit::WebView::WebViewPolicyDecisionSignalType& WebView::PolicyDecisionSignal()
+Dali::Toolkit::WebView::WebViewResponsePolicyDecisionSignalType& WebView::ResponsePolicyDecisionSignal()
{
- return mPolicyDecisionSignal;
+ return mResponsePolicyDecisionSignal;
}
Dali::Toolkit::WebView::WebViewCertificateSignalType& WebView::CertificateConfirmSignal()
}
}
-void WebView::OnPolicyDecisionRequest(std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
+void WebView::OnResponsePolicyDecided(std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
{
- if(!mPolicyDecisionSignal.Empty())
+ if(!mResponsePolicyDecisionSignal.Empty())
{
Dali::Toolkit::WebView handle(GetOwner());
- mPolicyDecisionSignal.Emit(handle, std::move(decision));
+ mResponsePolicyDecisionSignal.Emit(handle, std::move(decision));
}
}
}
else if(0 == strcmp(signalName.c_str(), POLICY_DECISION))
{
- webView.PolicyDecisionSignal().Connect(tracker, functor);
+ webView.ResponsePolicyDecisionSignal().Connect(tracker, functor);
connected = true;
}
else if(0 == strcmp(signalName.c_str(), CERTIFICATE_CONFIRM_SIGNAL))
/**
* @copydoc Dali::Toolkit::WebView::GetFavicon()
*/
- Dali::Toolkit::ImageView& GetFavicon();
+ Dali::Toolkit::ImageView GetFavicon() const;
/**
* @copydoc Dali::Toolkit::WebView::LoadUrl()
Dali::Toolkit::WebView::WebViewConsoleMessageSignalType& ConsoleMessageSignal();
/**
- * @copydoc Dali::Toolkit::WebView::PolicyDecisionSignal()
+ * @copydoc Dali::Toolkit::WebView::ResponsePolicyDecisionSignal()
*/
- Dali::Toolkit::WebView::WebViewPolicyDecisionSignalType& PolicyDecisionSignal();
+ Dali::Toolkit::WebView::WebViewResponsePolicyDecisionSignalType& ResponsePolicyDecisionSignal();
/**
* @copydoc Dali::Toolkit::WebView::CertificateConfirmSignal()
* @param[in] pixel Pixel data
* @return The new image view
*/
- Dali::Toolkit::ImageView CreateImageView(Dali::PixelData pixel);
+ Dali::Toolkit::ImageView CreateImageView(Dali::PixelData pixel) const;
/**
* @brief Callback function to be called when page load started.
void OnConsoleMessage(std::shared_ptr<Dali::WebEngineConsoleMessage> message);
/**
- * @brief Callback function to be called when policy need be decided.
+ * @brief Callback function to be called when response policy need be decided.
* @param[in] decision The policy decided.
*/
- void OnPolicyDecisionRequest(std::shared_ptr<Dali::WebEnginePolicyDecision> decision);
+ void OnResponsePolicyDecided(std::shared_ptr<Dali::WebEnginePolicyDecision> decision);
/**
* @brief Callback function to be called when certificate need be confirmed.
Dali::Toolkit::WebView::WebViewFrameRenderedSignalType mFrameRenderedSignal;
Dali::Toolkit::WebView::WebViewRequestInterceptorSignalType mRequestInterceptorSignal;
Dali::Toolkit::WebView::WebViewConsoleMessageSignalType mConsoleMessageSignal;
- Dali::Toolkit::WebView::WebViewPolicyDecisionSignalType mPolicyDecisionSignal;
+ Dali::Toolkit::WebView::WebViewResponsePolicyDecisionSignalType mResponsePolicyDecisionSignal;
Dali::Toolkit::WebView::WebViewCertificateSignalType mCertificateConfirmSignal;
Dali::Toolkit::WebView::WebViewCertificateSignalType mSslCertificateChangedSignal;
Dali::Toolkit::WebView::WebViewHttpAuthHandlerSignalType mHttpAuthHandlerSignal;
std::unique_ptr<Dali::Toolkit::WebSettings> mWebSettings;
std::unique_ptr<Dali::Toolkit::WebBackForwardList> mWebBackForwardList;
- Dali::Toolkit::ImageView mFaviconView;
-
Dali::PropertyNotification mPositionUpdateNotification;
Dali::PropertyNotification mSizeUpdateNotification;
Dali::PropertyNotification mScaleUpdateNotification;
${toolkit_src_dir}/focus-manager/keyboard-focus-manager-impl.cpp
${toolkit_src_dir}/focus-manager/keyinput-focus-manager-impl.cpp
+ ${toolkit_src_dir}/focus-manager/focus-finder-impl.cpp
${toolkit_src_dir}/helpers/color-conversion.cpp
${toolkit_src_dir}/helpers/property-helper.cpp
${toolkit_src_dir}/filters/blur-two-pass-filter.cpp
${toolkit_src_dir}/text/property-string-parser.cpp
${toolkit_src_dir}/text/segmentation.cpp
${toolkit_src_dir}/text/shaper.cpp
+ ${toolkit_src_dir}/text/hyphenator.cpp
${toolkit_src_dir}/text/text-enumerations-impl.cpp
${toolkit_src_dir}/text/text-controller.cpp
${toolkit_src_dir}/text/text-controller-event-handler.cpp
--- /dev/null
+/*\r
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (C) 2017 The Android Open Source Project\r
+ *\r
+ * Modified by joogab yun(joogab.yun@samsung.com)\r
+ */\r
+\r
+// CLASS HEADER\r
+#include "focus-finder-impl.h"\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/devel-api/actors/actor-devel.h>\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/integration-api/adaptor-framework/adaptor.h>\r
+#include <dali/integration-api/adaptor-framework/scene-holder.h>\r
+#include <dali/integration-api/debug.h>\r
+#include <dali/public-api/actors/layer.h>\r
+#include <math.h>\r
+\r
+namespace\r
+{\r
+static int MajorAxisDistanceRaw(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+ switch(direction)\r
+ {\r
+ case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+ {\r
+ return source.left - dest.right;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+ {\r
+ return dest.left - source.right;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+ {\r
+ return source.top - dest.bottom;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+ {\r
+ return dest.top - source.bottom;\r
+ }\r
+ default:\r
+ {\r
+ return 0;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * @return The distance from the edge furthest in the given direction\r
+ * of source to the edge nearest in the given direction of dest.\r
+ * If the dest is not in the direction from source, return 0.\r
+ */\r
+static int MajorAxisDistance(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+ return std::max(0, MajorAxisDistanceRaw(direction, source, dest));\r
+}\r
+\r
+static int MajorAxisDistanceToFarEdgeRaw(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+ switch(direction)\r
+ {\r
+ case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+ {\r
+ return source.left - dest.left;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+ {\r
+ return dest.right - source.right;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+ {\r
+ return source.top - dest.top;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+ {\r
+ return dest.bottom - source.bottom;\r
+ }\r
+ default:\r
+ {\r
+ return 0;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * @return The distance along the major axis w.r.t the direction from the\r
+ * edge of source to the far edge of dest.\r
+ * If the dest is not in the direction from source, return 1\r
+ */\r
+static int MajorAxisDistanceToFarEdge(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+ return std::max(1, MajorAxisDistanceToFarEdgeRaw(direction, source, dest));\r
+}\r
+\r
+/**\r
+ * Find the distance on the minor axis w.r.t the direction to the nearest\r
+ * edge of the destination rectangle.\r
+ * @param direction the direction (up, down, left, right)\r
+ * @param source The source rect.\r
+ * @param dest The destination rect.\r
+ * @return The distance.\r
+ */\r
+static int MinorAxisDistance(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+ switch(direction)\r
+ {\r
+ case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+ case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+ {\r
+ // the distance between the center verticals\r
+ return std::abs(\r
+ (((source.top + source.bottom) * 0.5f) -\r
+ (((dest.top + dest.bottom) * 0.5f))));\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+ case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+ {\r
+ // the distance between the center horizontals\r
+ return std::abs(\r
+ (((source.left + source.right) * 0.5f) -\r
+ (((dest.left + dest.right) * 0.5f))));\r
+ }\r
+ default:\r
+ {\r
+ return 0;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * Calculate distance given major and minor axis distances.\r
+ * @param majorAxisDistance The majorAxisDistance\r
+ * @param minorAxisDistance The minorAxisDistance\r
+ * @return The distance\r
+ */\r
+static int GetWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance)\r
+{\r
+ return 13 * majorAxisDistance * majorAxisDistance + minorAxisDistance * minorAxisDistance;\r
+}\r
+\r
+/**\r
+ * Convert x,y,width,height coordinates into left, right, bottom, top coordinates.\r
+ * @param[in,out] rect The rect\r
+ */\r
+static void ConvertCoordinate(Dali::Rect<float>& rect)\r
+{\r
+ // convert x, y, width, height -> left, right, bottom, top\r
+ float left = rect.x;\r
+ float right = rect.x + rect.width;\r
+ float bottom = rect.y + rect.height;\r
+ float top = rect.y;\r
+\r
+ rect.left = left;\r
+ rect.right = right;\r
+ rect.bottom = bottom;\r
+ rect.top = top;\r
+}\r
+\r
+/**\r
+ * Is destRect a candidate for the next focus given the direction?\r
+ * @param srcRect The source rect.\r
+ * @param destRect The dest rect.\r
+ * @param direction The direction (up, down, left, right)\r
+ * @return Whether destRect is a candidate.\r
+ */\r
+static bool IsCandidate(Dali::Rect<float> srcRect, Dali::Rect<float> destRect, Dali::Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+ switch(direction)\r
+ {\r
+ case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+ {\r
+ return (srcRect.right > destRect.right || srcRect.left >= destRect.right) && srcRect.left > destRect.left;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+ {\r
+ return (srcRect.left < destRect.left || srcRect.right <= destRect.left) && srcRect.right < destRect.right;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+ {\r
+ return (srcRect.bottom > destRect.bottom || srcRect.top >= destRect.bottom) && srcRect.top > destRect.top;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+ {\r
+ return (srcRect.top < destRect.top || srcRect.bottom <= destRect.top) && srcRect.bottom < destRect.bottom;\r
+ }\r
+ default:\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r
+/**\r
+ * Is dest in a given direction from src?\r
+ * @param direction the direction (up, down, left, right)\r
+ * @param src The source rect\r
+ * @param dest The dest rect\r
+ */\r
+static bool IsToDirectionOf(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> src, Dali::Rect<float> dest)\r
+{\r
+ switch(direction)\r
+ {\r
+ case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+ {\r
+ return src.left >= dest.right;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+ {\r
+ return src.right <= dest.left;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+ {\r
+ return src.top >= dest.bottom;\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+ {\r
+ return src.bottom <= dest.top;\r
+ }\r
+ default:\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * Do the given direction's axis of rect1 and rect2 overlap?\r
+ * @param direction the direction (up, down, left, right)\r
+ * @param rect1 The first rect\r
+ * @param rect2 The second rect\r
+ * @return whether the beams overlap\r
+ */\r
+static bool BeamsOverlap(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> rect1, Dali::Rect<float> rect2)\r
+{\r
+ switch(direction)\r
+ {\r
+ case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+ case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+ {\r
+ return (rect2.bottom >= rect1.top) && (rect2.top <= rect1.bottom);\r
+ }\r
+ case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+ case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+ {\r
+ return (rect2.right >= rect1.left) && (rect2.left <= rect1.right);\r
+ }\r
+ default:\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * One rectangle may be another candidate than another by virtue of being exclusively in the beam of the source rect.\r
+ * @param direction The direction (up, down, left, right)\r
+ * @param source The source rect\r
+ * @param rect1 The first rect\r
+ * @param rect2 The second rect\r
+ * @return Whether rect1 is a better candidate than rect2 by virtue of it being in src's beam\r
+ */\r
+static bool BeamBeats(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> rect1, Dali::Rect<float> rect2)\r
+{\r
+ const bool rect1InSrcBeam = BeamsOverlap(direction, source, rect1);\r
+ const bool rect2InSrcBeam = BeamsOverlap(direction, source, rect2);\r
+ // if rect1 isn't exclusively in the src beam, it doesn't win\r
+ if(rect2InSrcBeam || !rect1InSrcBeam)\r
+ {\r
+ return false;\r
+ }\r
+ // we know rect1 is in the beam, and rect2 is not\r
+ // if rect1 is to the direction of, and rect2 is not, rect1 wins.\r
+ // for example, for direction left, if rect1 is to the left of the source\r
+ // and rect2 is below, then we always prefer the in beam rect1, since rect2\r
+ // could be reached by going down.\r
+ if(!IsToDirectionOf(direction, source, rect2))\r
+ {\r
+ return true;\r
+ }\r
+ // for horizontal directions, being exclusively in beam always wins\r
+ if((direction == Dali::Toolkit::Control::KeyboardFocus::LEFT || direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT))\r
+ {\r
+ return true;\r
+ }\r
+ // for vertical directions, beams only beat up to a point:\r
+ // now, as long as rect2 isn't completely closer, rect1 wins\r
+ // e.g for direction down, completely closer means for rect2's top\r
+ // edge to be closer to the source's top edge than rect1's bottom edge.\r
+ return (MajorAxisDistance(direction, source, rect1) < MajorAxisDistanceToFarEdge(direction, source, rect2));\r
+}\r
+\r
+} // unnamed namespace\r
+\r
+namespace Dali\r
+{\r
+namespace Toolkit\r
+{\r
+namespace Internal\r
+{\r
+FocusFinder::FocusFinder()\r
+{\r
+}\r
+\r
+FocusFinder::~FocusFinder()\r
+{\r
+}\r
+\r
+Actor FocusFinder::GetNearestFocusableActor(Actor& focusedActor, Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+ Actor nearestActor;\r
+ if(!focusedActor)\r
+ {\r
+ return nearestActor;\r
+ }\r
+\r
+ Rect<float> focusedRect = DevelActor::CalculateScreenExtents(focusedActor);\r
+\r
+ // initialize the best candidate to something impossible\r
+ // (so the first plausible actor will become the best choice)\r
+ Rect<float> bestCandidateRect = focusedRect;\r
+ switch(direction)\r
+ {\r
+ case Toolkit::Control::KeyboardFocus::LEFT:\r
+ {\r
+ bestCandidateRect.x += 1;\r
+ break;\r
+ }\r
+ case Toolkit::Control::KeyboardFocus::RIGHT:\r
+ {\r
+ bestCandidateRect.x -= 1;\r
+ break;\r
+ }\r
+ case Toolkit::Control::KeyboardFocus::UP:\r
+ {\r
+ bestCandidateRect.y += 1;\r
+ break;\r
+ }\r
+ case Toolkit::Control::KeyboardFocus::DOWN:\r
+ {\r
+ bestCandidateRect.y -= 1;\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ ConvertCoordinate(bestCandidateRect);\r
+\r
+ ConvertCoordinate(focusedRect);\r
+\r
+ Integration::SceneHolder window = Integration::SceneHolder::Get(focusedActor);\r
+ if(window)\r
+ {\r
+ Actor rootActor = window.GetRootLayer();\r
+ nearestActor = FindNextFocus(rootActor, focusedActor, focusedRect, bestCandidateRect, direction);\r
+ }\r
+ return nearestActor;\r
+}\r
+\r
+Actor FocusFinder::FindNextFocus(Actor& actor, Actor& focusedActor, Rect<float>& focusedRect, Rect<float>& bestCandidateRect, Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+ Actor nearestActor;\r
+ if(actor)\r
+ {\r
+ // Recursively children\r
+ const auto childCount = actor.GetChildCount();\r
+ for(auto i = 0u; i < childCount; ++i)\r
+ {\r
+ Dali::Actor child = actor.GetChildAt(i);\r
+ if(child && child != focusedActor && child.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))\r
+ {\r
+ Rect<float> candidateRect = DevelActor::CalculateScreenExtents(child);\r
+\r
+ // convert x, y, width, height -> left, right, bottom, top\r
+ ConvertCoordinate(candidateRect);\r
+\r
+ if(IsBetterCandidate(direction, focusedRect, candidateRect, bestCandidateRect))\r
+ {\r
+ bestCandidateRect = candidateRect;\r
+ nearestActor = child;\r
+ }\r
+ }\r
+ Actor nextActor = FindNextFocus(child, focusedActor, focusedRect, bestCandidateRect, direction);\r
+ if(nextActor)\r
+ {\r
+ nearestActor = nextActor;\r
+ }\r
+ }\r
+ }\r
+ return nearestActor;\r
+}\r
+\r
+bool FocusFinder::IsBetterCandidate(Toolkit::Control::KeyboardFocus::Direction direction, Rect<float>& focusedRect, Rect<float>& candidateRect, Rect<float>& bestCandidateRect) const\r
+{\r
+ // to be a better candidate, need to at least be a candidate in the first place\r
+ if(!IsCandidate(focusedRect, candidateRect, direction))\r
+ {\r
+ return false;\r
+ }\r
+ // we know that candidateRect is a candidate.. if bestCandidateRect is not a candidate,\r
+ // candidateRect is better\r
+ if(!IsCandidate(focusedRect, bestCandidateRect, direction))\r
+ {\r
+ return true;\r
+ }\r
+ // if candidateRect is better by beam, it wins\r
+ if(BeamBeats(direction, focusedRect, candidateRect, bestCandidateRect))\r
+ {\r
+ return true;\r
+ }\r
+ // if bestCandidateRect is better, then candidateRect cant' be :)\r
+ if(BeamBeats(direction, focusedRect, bestCandidateRect, candidateRect))\r
+ {\r
+ return false;\r
+ }\r
+\r
+ // otherwise, do fudge-tastic comparison of the major and minor axis\r
+ return (GetWeightedDistanceFor(\r
+ MajorAxisDistance(direction, focusedRect, candidateRect),\r
+ MinorAxisDistance(direction, focusedRect, candidateRect)) < GetWeightedDistanceFor(MajorAxisDistance(direction, focusedRect, bestCandidateRect),\r
+ MinorAxisDistance(direction, focusedRect, bestCandidateRect)));\r
+}\r
+\r
+} // namespace Internal\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_FOCUS_FINDER_H\r
+#define DALI_TOOLKIT_INTERNAL_FOCUS_FINDER_H\r
+\r
+/*\r
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/public-api/object/base-object.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/devel-api/focus-manager/focus-finder.h>\r
+\r
+namespace Dali\r
+{\r
+namespace Integration\r
+{\r
+class SceneHolder;\r
+\r
+} // namespace Integration\r
+\r
+namespace Toolkit\r
+{\r
+namespace Internal\r
+{\r
+class FocusFinder;\r
+\r
+/**\r
+ * @copydoc Toolkit::FocusFinder\r
+ */\r
+class FocusFinder : public Dali::BaseObject\r
+{\r
+public:\r
+ /**\r
+ * Construct a new FocusFinder.\r
+ */\r
+ FocusFinder();\r
+\r
+ /**\r
+ * @copydoc Toolkit::GetNearestFocusableActor\r
+ */\r
+ Actor GetNearestFocusableActor(Actor& focusedActor, Toolkit::Control::KeyboardFocus::Direction direction);\r
+\r
+protected:\r
+ /**\r
+ * Destructor\r
+ */\r
+ virtual ~FocusFinder();\r
+\r
+private:\r
+ /**\r
+ * Find the next actor to take focus in root's descendants, starting from the actor.\r
+ * @param[in] actor The root actor.\r
+ * @param[in] focusedActor The current focused actor.\r
+ * @param[in] focusedRect The rect of current focused actor.\r
+ * @param[in] bestCandidateRect The current best candidate.\r
+ * @param[in] direction The direction.\r
+ * @return nearest Actor.\r
+ */\r
+ Actor FindNextFocus(Actor& actor, Actor& focusedActor, Rect<float>& focusedRect, Rect<float>& bestCandidateRect, Toolkit::Control::KeyboardFocus::Direction direction);\r
+\r
+ /**\r
+ * Is rect1 a better candidate than rect2 for a focus search in a particular\r
+ * direction from a source rect? This is the core routine that determines\r
+ * the order of focus searching.\r
+ * @param direction The direction (up, down, left, right)\r
+ * @param candidateRect The candidate rectangle\r
+ * @param bestCandidateRect The current best candidate.\r
+ * @return Whether the candidate is the new best.\r
+ */\r
+ bool IsBetterCandidate(Toolkit::Control::KeyboardFocus::Direction direction, Rect<float>& focusedRect, Rect<float>& candidateRect, Rect<float>& bestCandidateRect) const;\r
+\r
+private:\r
+ // Undefined\r
+ FocusFinder(const FocusFinder&);\r
+\r
+ FocusFinder& operator=(const FocusFinder& rhs);\r
+};\r
+\r
+} // namespace Internal\r
+\r
+inline Internal::FocusFinder& GetImpl(Dali::Toolkit::FocusFinder& obj)\r
+{\r
+ DALI_ASSERT_ALWAYS(obj);\r
+\r
+ Dali::BaseObject& handle = obj.GetBaseObject();\r
+\r
+ return static_cast<Internal::FocusFinder&>(handle);\r
+}\r
+\r
+inline const Internal::FocusFinder& GetImpl(const Dali::Toolkit::FocusFinder& obj)\r
+{\r
+ DALI_ASSERT_ALWAYS(obj);\r
+\r
+ const Dali::BaseObject& handle = obj.GetBaseObject();\r
+\r
+ return static_cast<const Internal::FocusFinder&>(handle);\r
+}\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_INTERNAL_FOCUS_FINDER_H\r
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/focus-manager/focus-finder.h>
#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/public-api/controls/control.h>
nextFocusableActor = mPreFocusChangeSignal.Emit(currentFocusActor, Actor(), direction);
mIsWaitingKeyboardFocusChangeCommit = false;
}
+ else
+ {
+ // We should find it among the actors nearby.
+ nextFocusableActor = Toolkit::FocusFinder::Get().GetNearestFocusableActor(currentFocusActor, direction);
+ }
}
if(nextFocusableActor && nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
+++ /dev/null
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform mediump float blurRadius;
-
-void main()
-{
- OUT_COLOR = vec4(mixColor, 1.0) * uColor;
- if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
- {
- return;
- }
-
- mediump float radius =
- mix(
- mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
- mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
- sign(vPosition.y) * 0.5 + 0.5
- );
-
- mediump vec2 v = abs(vPosition) - vRectSize + radius;
- mediump float cy = radius + blurRadius;
- mediump float cr = radius + blurRadius;
-
- cy = min(cy, min(vRectSize.x, vRectSize.y) - radius);
- v = vec2(min(v.x, v.y), max(v.x, v.y));
- v = v + cy;
-
- mediump float blur = 1.0;
- mediump float potential = 0.0;
- mediump float alias = min(radius, 1.0);
- mediump float potentialMin = cy + radius - blurRadius - alias;
- mediump float potentialMax = cy + radius + blurRadius + alias;
-
- // move center of circles for reduce defact
- mediump float cyDiff = min(cy, 0.2 * blurRadius);
- cy -= cyDiff;
- cr += cyDiff;
-
- mediump float diffFromBaseline = cy * v.y - (cy + cr) * v.x;
-
- if(diffFromBaseline > 0.0)
- {
- // out of calculation bound.
- potential = v.y;
-
- // for anti-alias when blurRaidus = 0.0
- mediump float heuristicBaselineScale = max(1.0 , cr * (cr + cy));
- mediump float potentialDiff = min(alias, diffFromBaseline / heuristicBaselineScale);
- potentialMin += potentialDiff;
- potentialMax -= potentialDiff;
- }
- else
- {
- // get some circle centered (x, x) and radius (r = cr / cy * x)
- // s.t. point v is on that circle
- // highest point of that circle is (x, x + r) and potential is x + r
-
- // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
-
- mediump float A = (cr * cr - 2.0 * cy * cy);
- mediump float B = cy * (v.x + v.y);
- mediump float V = dot(v,v);
- mediump float D = B * B + A * V;
- potential = V * (cr + cy) / (sqrt(D) + B);
- }
-
- blur = 1.0 - smoothstep(potentialMin, potentialMax, potential);
- OUT_COLOR.a *= blur;
-}
+++ /dev/null
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec2 extraSize;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump float blurRadius;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
- vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
- mediump float minSize = min( visualSize.x, visualSize.y );
- vCornerRadius = mix( cornerRadius * minSize, cornerRadius, cornerRadiusPolicy );
- vCornerRadius = min( vCornerRadius, minSize * 0.5 );
- vRectSize = visualSize / 2.0;
- // optimize fragment shader
- mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
- vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0 - blurRadius;
-
- vPosition = aPosition * (visualSize + 2.0 * blurRadius);
- return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
- gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
+++ /dev/null
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-
-void main()
-{
- OUT_COLOR = vec4(mixColor, 1.0) * uColor;
- if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
- {
- return;
- }
- mediump float radius =
- mix(
- mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
- mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
- sign(vPosition.y) * 0.5 + 0.5
- );
-
- mediump vec2 diff = abs(vPosition) - vRectSize + radius;
- mediump float dist = length(max(diff, vec2(0.0))) - radius;
- if(dist > 1.0)
- {
- OUT_COLOR.a = 0.0;
- }
- else if(dist > -1.0)
- {
- if(min(diff.x, diff.y) < 0.0)
- {
- dist += min(diff.x, diff.y) / max(radius, 1.0);
- }
- OUT_COLOR.a *= 1.0 - smoothstep(-1.0, 1.0, dist);
- }
-}
+++ /dev/null
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec2 extraSize;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
- vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
- mediump float minSize = min( visualSize.x, visualSize.y );
- vCornerRadius = mix( cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
- vCornerRadius = min( vCornerRadius, minSize * 0.5 );
- vRectSize = visualSize / 2.0;
- // optimize fragment shader
- mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
- vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
- vPosition = aPosition* visualSize;
- return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
- gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef IS_REQUIRED_BLUR
+#define IS_REQUIRED_BLUR 0
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
uniform lowp vec4 uColor;
uniform lowp vec3 mixColor;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+#if IS_REQUIRED_BLUR
+uniform mediump float blurRadius;
+#endif
+
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+ gRadius =
+ mix(
+ mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+ mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+ sign(vPosition.y) * 0.5 + 0.5
+ );
+#endif
+}
+
+void calculatePosition()
+{
+ gFragmentPosition = abs(vPosition) - vRectSize;
+ gCenterPosition = -gRadius;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+ gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+ gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+ gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+ gPotentialRange = 1.0;
+
+ gMaxOutlinePotential = gRadius + gPotentialRange;
+ gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+ gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+ gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+ gMaxInlinePotential = gMaxOutlinePotential;
+ gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+ // reduce defect near edge of rounded corner.
+ gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+ gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+ calculateCornerRadius();
+ calculatePosition();
+ calculatePotential();
+
+ setupMinMaxPotential();
+}
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+ mediump float potential = gPotential;
+
+ // default opacity of borderline is 0.0
+ mediump float borderlineOpacity = 0.0;
+
+ // calculate borderline opacity by potential
+ if(potential > gMinInlinePotential)
+ {
+ // potential is inside borderline range.
+ borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+ }
+
+ //calculate inside of borderline when outilneColor.a < 1.0
+ if(borderlineColor.a < 1.0)
+ {
+ mediump float tCornerRadius = -gCenterPosition;
+ mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+ mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+ if(potential > MaxTexturelinePotential)
+ {
+ // potential is out of texture range. use borderline color instead of texture
+ textureColor = vec4(borderlineColor.xyz, 0.0);
+ }
+ else if(potential > MinTexturelinePotential)
+ {
+ // potential is in texture range
+ textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+ }
+ borderlineOpacity *= borderlineColor.a;
+ }
+ return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+ mediump float potential = gPotential;
+
+ // default opacity is 1.0
+ mediump float opacity = 1.0;
+
+ // calculate borderline opacity by potential
+ if(potential > gMaxOutlinePotential)
+ {
+ // potential is out of borderline range
+ opacity = 0.0;
+ }
+ else if(potential > gMinOutlinePotential)
+ {
+ opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+ }
+ return opacity;
+}
+#endif
+
+#if IS_REQUIRED_BLUR
+mediump float calculateBlurOpacity()
+{
+// Don't use borderline!
+ mediump vec2 v = gDiff;
+ mediump float cy = gRadius + blurRadius;
+ mediump float cr = gRadius + blurRadius;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+ // This routine make perfect circle. If corner radius is not exist, we don't consider prefect circle.
+ cy = min(cy, min(vRectSize.x, vRectSize.y) - gRadius);
+#endif
+ v = vec2(min(v.x, v.y), max(v.x, v.y));
+ v = v + cy;
+
+ mediump float potential = 0.0;
+ mediump float alias = min(gRadius, 1.0);
+ mediump float potentialMin = cy + gRadius - blurRadius - alias;
+ mediump float potentialMax = cy + gRadius + blurRadius + alias;
+
+ // move center of circles for reduce defact
+ mediump float cyDiff = min(cy, 0.2 * blurRadius);
+ cy -= cyDiff;
+ cr += cyDiff;
+
+ mediump float diffFromBaseline = cy * v.y - (cy + cr) * v.x;
+
+ if(diffFromBaseline > 0.0)
+ {
+ // out of calculation bound.
+ potential = v.y;
+
+ // for anti-alias when blurRaidus = 0.0
+ mediump float heuristicBaselineScale = max(1.0 , cr * (cr + cy));
+ mediump float potentialDiff = min(alias, diffFromBaseline / heuristicBaselineScale);
+ potentialMin += potentialDiff;
+ potentialMax -= potentialDiff;
+ }
+ else
+ {
+ // get some circle centered (x, x) and radius (r = cr / cy * x)
+ // s.t. point v is on that circle
+ // highest point of that circle is (x, x + r) and potential is x + r
+
+ // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
+#if IS_REQUIRED_ROUNDED_CORNER
+ // NOTE : lowspec HW cannot calculate here. need to reduce numeric error
+ mediump float A = (cr * cr - 2.0 * cy * cy);
+ mediump float B = cy * (v.x + v.y);
+ mediump float V = dot(v,v);
+ mediump float D = B * B + A * V;
+ potential = V * (cr + cy) / (sqrt(D) + B);
+#else
+ // We can simplify this value cause cy = 0.8 * blurRadius, cr = 1.2 * blurRadius
+ // potential = 5.0*(sqrt(4.0*(v.x+v.y)^2 + dot(v,v)) - 2.0*(v.x+v.y));
+ // = 10.0*(v.x+v.y) * (sqrt(1.0 + (length(v) / (2.0*(v.x+v.y)))^2) - 1.0);
+ // = 10.0*(v.x+v.y) * (sqrt(1.25 - x + x^2) - 1.0);
+ // ~= 10.0*(v.x+v.y) * (0.11803399 - 0.44721360x + 0.35777088x^2 - 0.14310x^3 + O(x^4)) (Taylor series)
+ // ~= -1.0557281 * (v.x + v.y) + 2.236068 * length(v) - ~~~ (here, x <= 0.5 * (1.0 - sqrt(0.5)) < 0.1464467)
+ // Note : This simplify need cause we should use it on lowspec HW.
+ mediump float x = 0.5 * (1.0 - length(v) / (v.x + v.y));
+ potential = -1.0557281 * (v.x + v.y) + 2.236068 * length(v) + 10.0 * (v.x + v.y) * (0.35777088 - 0.14310 * x) * x * x;
+#endif
+ }
+
+ return 1.0 - smoothstep(potentialMin, potentialMax, potential);
+}
+#endif
void main()
{
- OUT_COLOR = vec4(mixColor, 1.0) * uColor;
-}
\ No newline at end of file
+ lowp vec4 targetColor = vec4(mixColor, 1.0) * uColor;
+
+#if IS_REQUIRED_BLUR || IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ // skip most potential calculate for performance
+ if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+ {
+ OUT_COLOR = targetColor;
+ return;
+ }
+ PreprocessPotential();
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+ targetColor = convertBorderlineColor(targetColor);
+#endif
+ OUT_COLOR = targetColor;
+
+#if IS_REQUIRED_BLUR
+ mediump float opacity = calculateBlurOpacity();
+ OUT_COLOR.a *= opacity;
+#elif IS_REQUIRED_ROUNDED_CORNER
+ mediump float opacity = calculateCornerOpacity();
+ OUT_COLOR.a *= opacity;
+#endif
+}
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef IS_REQUIRED_BLUR
+#define IS_REQUIRED_BLUR 0
+#endif
+
INPUT mediump vec2 aPosition;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
uniform highp mat4 uMvpMatrix;
uniform highp vec3 uSize;
uniform mediump vec4 offsetSizeMode;
uniform mediump vec2 origin;
uniform mediump vec2 anchorPoint;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_BLUR
+uniform mediump float blurRadius;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
uniform mediump vec2 extraSize;
vec4 ComputeVertexPosition()
{
vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
- vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
- return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+ vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+ vRectSize = visualSize * 0.5;
+ vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+ mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+ mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+ vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+ vCornerRadius = min(vCornerRadius, minSize * 0.5);
+ // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+ mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+ vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BLUR
+ vPosition = aPosition * (visualSize + 2.0 * blurRadius);
+ vOptRectSize -= blurRadius + 1.0;
+#elif IS_REQUIRED_BORDERLINE
+ vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0))* borderlineWidth);
+ vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+ vPosition = aPosition * visualSize;
+#else
+ mediump vec2 vPosition = aPosition * visualSize;
+#endif
+ return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
}
void main()
{
gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
\ No newline at end of file
+}
--- /dev/null
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+
+#ifndef GLYPHY_INFINITY
+#define GLYPHY_INFINITY 1e9
+#endif
+#ifndef GLYPHY_EPSILON
+#define GLYPHY_EPSILON 1e-5
+#endif
+
+#ifndef GLYPHY_RGBA
+#ifdef GLYPHY_BGRA
+#define GLYPHY_RGBA(v) glyphy_bgra (v)
+#else
+#define GLYPHY_RGBA(v) glyphy_rgba (v)
+#endif
+#endif
+
+vec4 glyphy_rgba (const vec4 v)
+{
+ return v.rgba;
+}
+
+vec4 glyphy_bgra (const vec4 v)
+{
+ return v.bgra;
+}
+
+struct glyphy_arc_t
+{
+ vec2 p0;
+ vec2 p1;
+ float d;
+};
+
+struct glyphy_arc_endpoint_t
+{
+ /* Second arc endpoint */
+ vec2 p;
+ /* Infinity if this endpoint does not form an arc with the previous
+ * endpoint. Ie. a \"move_to\". Test with glyphy_isinf().
+ * Arc depth otherwise. */
+ float d;
+};
+
+struct glyphy_arc_list_t
+{
+ /* Number of endpoints in the list.
+ * Will be zero if we're far away inside or outside, in which case side is set.
+ * Will be -1 if this arc-list encodes a single line, in which case line_* are set. */
+ int num_endpoints;
+
+ /* If num_endpoints is zero, this specifies whether we are inside (-1)
+ * or outside (+1). Otherwise we're unsure (0). */
+ int side;
+ /* Offset to the arc-endpoints from the beginning of the glyph blob */
+ int offset;
+
+ /* A single line is all we care about. It's right here. */
+ float line_angle;
+ float line_distance; /* From nominal glyph center */
+};
+
+bool glyphy_isinf (const float v)
+{
+ return abs (v) >= GLYPHY_INFINITY * .5;
+}
+
+bool glyphy_iszero (const float v)
+{
+ return abs (v) <= GLYPHY_EPSILON * 2.;
+}
+
+vec2 glyphy_ortho (const vec2 v)
+{
+ return vec2 (-v.y, v.x);
+}
+
+int glyphy_float_to_byte (const float v)
+{
+ return int (v * (256. - GLYPHY_EPSILON));
+}
+
+ivec4 glyphy_vec4_to_bytes (const vec4 v)
+{
+ return ivec4 (v * (256. - GLYPHY_EPSILON));
+}
+
+ivec2 glyphy_float_to_two_nimbles (const float v)
+{
+ int f = glyphy_float_to_byte (v);
+ return ivec2 (f / 16, int(mod (float(f), 16.)));
+}
+
+/* returns tan (2 * atan (d)) */
+float glyphy_tan2atan (const float d)
+{
+ return 2. * d / (1. - d * d);
+}
+
+glyphy_arc_endpoint_t glyphy_arc_endpoint_decode(const vec4 v, const ivec2 nominal_size)
+{
+ vec2 p = (vec2 (glyphy_float_to_two_nimbles (v.a)) + v.gb) / 16.;
+ float d = v.r;
+ if (d == 0.)
+ d = GLYPHY_INFINITY;
+ else
+#define GLYPHY_MAX_D .5
+ d = float(glyphy_float_to_byte (d) - 128) * GLYPHY_MAX_D / 127.;
+#undef GLYPHY_MAX_D
+ return glyphy_arc_endpoint_t (p * vec2(nominal_size), d);
+}
+
+vec2 glyphy_arc_center (const glyphy_arc_t a)
+{
+ return mix (a.p0, a.p1, .5) +
+ glyphy_ortho (a.p1 - a.p0) / (2. * glyphy_tan2atan (a.d));
+}
+
+bool glyphy_arc_wedge_contains (const glyphy_arc_t a, const vec2 p)
+{
+ float d2 = glyphy_tan2atan (a.d);
+ return dot (p - a.p0, (a.p1 - a.p0) * mat2(1, d2, -d2, 1)) >= 0. &&
+ dot (p - a.p1, (a.p1 - a.p0) * mat2(1, -d2, d2, 1)) <= 0.;
+}
+
+float glyphy_arc_wedge_signed_dist_shallow (const glyphy_arc_t a, const vec2 p)
+{
+ vec2 v = normalize (a.p1 - a.p0);
+ float line_d = dot (p - a.p0, glyphy_ortho (v));
+ if (a.d == 0.)
+ return line_d;
+
+ float d0 = dot ((p - a.p0), v);
+ if (d0 < 0.)
+ return sign (line_d) * distance (p, a.p0);
+ float d1 = dot ((a.p1 - p), v);
+ if (d1 < 0.)
+ return sign (line_d) * distance (p, a.p1);
+ float r = 2. * a.d * (d0 * d1) / (d0 + d1);
+ if (r * line_d > 0.)
+ return sign (line_d) * min (abs (line_d + r), min (distance (p, a.p0), distance (p, a.p1)));
+ return line_d + r;
+}
+
+float glyphy_arc_wedge_signed_dist (const glyphy_arc_t a, const vec2 p)
+{
+ if (abs (a.d) <= .03)
+ return glyphy_arc_wedge_signed_dist_shallow (a, p);
+ vec2 c = glyphy_arc_center (a);
+ return sign (a.d) * (distance (a.p0, c) - distance (p, c));
+}
+
+float glyphy_arc_extended_dist (const glyphy_arc_t a, const vec2 p)
+{
+ /* Note: this doesn't handle points inside the wedge. */
+ vec2 m = mix (a.p0, a.p1, .5);
+ float d2 = glyphy_tan2atan (a.d);
+ if (dot (p - m, a.p1 - m) < 0.)
+ return dot (p - a.p0, normalize ((a.p1 - a.p0) * mat2(+d2, -1, +1, +d2)));
+ else
+ return dot (p - a.p1, normalize ((a.p1 - a.p0) * mat2(-d2, -1, +1, -d2)));
+}
+
+int glyphy_arc_list_offset (const vec2 p, const ivec2 nominal_size)
+{
+ ivec2 cell = ivec2 (clamp (floor (p), vec2 (0.,0.), vec2(nominal_size - 1)));
+ return cell.y * nominal_size.x + cell.x;
+}
+
+glyphy_arc_list_t glyphy_arc_list_decode (const vec4 v, const ivec2 nominal_size)
+{
+ glyphy_arc_list_t l;
+ ivec4 iv = glyphy_vec4_to_bytes (v);
+ l.side = 0; /* unsure */
+ if (iv.r == 0)
+ { /* arc-list encoded */
+ l.offset = (iv.g * 256) + iv.b;
+ l.num_endpoints = iv.a;
+ if (l.num_endpoints == 255)
+ {
+ l.num_endpoints = 0;
+ l.side = -1;
+ }
+ else if (l.num_endpoints == 0)
+ l.side = +1;
+ }
+ else
+ { /* single line encoded */
+ l.num_endpoints = -1;
+ l.line_distance = ( float(iv.r)/32. + 0.01*float(iv.g)/82.0 - 6.) * max (float (nominal_size.x), float (nominal_size.y));
+ l.line_angle = ( -float(iv.b)/40.74 - float( iv.a )*0.0001 )-3.142;
+ }
+ return l;
+}
--- /dev/null
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_TEXTURE1D_FUNC
+#define GLYPHY_TEXTURE1D_FUNC glyphy_texture1D_func
+#endif
+#ifndef GLYPHY_TEXTURE1D_EXTRA_DECLS
+#define GLYPHY_TEXTURE1D_EXTRA_DECLS
+#endif
+#ifndef GLYPHY_TEXTURE1D_EXTRA_ARGS
+#define GLYPHY_TEXTURE1D_EXTRA_ARGS
+#endif
+
+#ifndef GLYPHY_SDF_TEXTURE1D_FUNC
+#define GLYPHY_SDF_TEXTURE1D_FUNC GLYPHY_TEXTURE1D_FUNC
+#endif
+#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS
+#define GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS GLYPHY_TEXTURE1D_EXTRA_DECLS
+#endif
+#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS
+#define GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS GLYPHY_TEXTURE1D_EXTRA_ARGS
+#endif
+#ifndef GLYPHY_SDF_TEXTURE1D
+#define GLYPHY_SDF_TEXTURE1D(offset) GLYPHY_RGBA(GLYPHY_SDF_TEXTURE1D_FUNC (offset GLYPHY_TEXTURE1D_EXTRA_ARGS))
+#endif
+
+#ifndef GLYPHY_MAX_NUM_ENDPOINTS
+#define GLYPHY_MAX_NUM_ENDPOINTS 32
+#endif
+
+glyphy_arc_list_t glyphy_arc_list (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)
+{
+ int cell_offset = glyphy_arc_list_offset (p, nominal_size);
+ vec4 arc_list_data = GLYPHY_SDF_TEXTURE1D (cell_offset);
+ return glyphy_arc_list_decode (arc_list_data, nominal_size);
+}
+
+float glyphy_sdf (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)
+{
+ glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);
+
+ /* Short-circuits */
+ if (arc_list.num_endpoints == 0)
+ {
+ /* far-away cell */
+ return GLYPHY_INFINITY * float(arc_list.side);
+ }
+ if (arc_list.num_endpoints == -1)
+ {
+ /* single-line */
+ float angle = arc_list.line_angle;
+ vec2 n = vec2 (cos (angle), sin (angle));
+ return dot (p - (vec2(nominal_size) * .5), n) - arc_list.line_distance;
+ }
+
+ float side = float(arc_list.side);
+ float min_dist = GLYPHY_INFINITY;
+ glyphy_arc_t closest_arc;
+
+ glyphy_arc_endpoint_t endpoint_prev, endpoint;
+ endpoint_prev = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset), nominal_size);
+ for (int i = 1; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)
+ {
+ if (i >= arc_list.num_endpoints)
+ {
+ break;
+ }
+ endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);
+ glyphy_arc_t a = glyphy_arc_t (endpoint_prev.p, endpoint.p, endpoint.d);
+ endpoint_prev = endpoint;
+ if (glyphy_isinf (a.d)) continue;
+
+ if (glyphy_arc_wedge_contains (a, p))
+ {
+ float sdist = glyphy_arc_wedge_signed_dist (a, p);
+ float udist = abs (sdist) * (1. - GLYPHY_EPSILON);
+ if (udist <= min_dist)
+ {
+ min_dist = udist;
+ side = sign (sdist);
+ }
+ }
+ else
+ {
+ float udist = min (distance (p, a.p0), distance (p, a.p1));
+ if (udist < min_dist)
+ {
+ min_dist = udist;
+ side = 0.; /* unsure */
+ closest_arc = a;
+ }
+ else if (side == 0. && udist == min_dist)
+ {
+ /* If this new distance is the same as the current minimum,
+ * compare extended distances. Take the sign from the arc
+ * with larger extended distance. */
+ float old_ext_dist = glyphy_arc_extended_dist (closest_arc, p);
+ float new_ext_dist = glyphy_arc_extended_dist (a, p);
+
+ float ext_dist = abs (new_ext_dist) <= abs (old_ext_dist) ?
+ old_ext_dist : new_ext_dist;
+
+#ifdef GLYPHY_SDF_PSEUDO_DISTANCE
+ /* For emboldening and stuff: */
+ min_dist = abs (ext_dist);
+#endif
+ side = sign (ext_dist);
+ }
+ }
+ }
+
+ if (side == 0.)
+ {
+ // Technically speaking this should not happen, but it does. So try to fix it.
+ float ext_dist = glyphy_arc_extended_dist (closest_arc, p);
+ side = sign (ext_dist);
+ }
+
+ return min_dist * side;
+}
+
+float glyphy_point_dist (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)
+{
+ glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);
+
+ float side = float(arc_list.side);
+ float min_dist = GLYPHY_INFINITY;
+
+ if (arc_list.num_endpoints == 0)
+ return min_dist;
+
+ glyphy_arc_endpoint_t endpoint;
+ for (int i = 0; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)
+ {
+ if (i >= arc_list.num_endpoints)
+ {
+ break;
+ }
+ endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);
+ if (glyphy_isinf (endpoint.d)) continue;
+ min_dist = min (min_dist, distance (p, endpoint.p));
+ }
+
+ return min_dist;
+}
--- /dev/null
+#extension GL_OES_standard_derivatives : enable
+precision highp float;
+precision highp int;
--- /dev/null
+struct Material
+{
+ mediump float mOpacity;
+ mediump float mShininess;
+ lowp vec4 mAmbient;
+ lowp vec4 mDiffuse;
+ lowp vec4 mSpecular;
+ lowp vec4 mEmissive;
+};
+
+uniform sampler2D sTexture;
+uniform sampler2D sOpacityTexture;
+uniform sampler2D sNormalMapTexture;
+uniform sampler2D sEffect;
+varying mediump vec2 vTexCoord;
+uniform Material uMaterial;
+uniform lowp vec4 uColor;
+varying highp vec4 vVertex;
+varying highp vec3 vNormal;
+varying mediump vec4 vColor;
+uniform vec4 u_atlas_info;
+
+#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos
+#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos
+#define GLYPHY_DEMO_EXTRA_ARGS , sTexture, uu_atlas_info, gi.atlas_pos
+
+vec4 glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)
+{
+ ivec2 item_geom = _atlas_info.zw;
+ vec2 pos = (vec2 (_atlas_pos.xy * item_geom +
+ ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +
+ + vec2 (.5, .5)) / vec2(_atlas_info.xy);
+ return texture2D (_tex, pos);
+}
--- /dev/null
+uniform float u_contrast;
+uniform float u_gamma_adjust;
+uniform float u_outline_thickness;
+uniform float u_outline;
+uniform float u_boldness;
+
+varying vec4 v_glyph;
+
+#define SQRT2_2 0.70711 /* 1 / sqrt(2.) */
+#define SQRT2 1.41421
+
+struct glyph_info_t
+{
+ ivec2 nominal_size;
+ ivec2 atlas_pos;
+};
+
+glyph_info_t glyph_info_decode (vec4 v)
+{
+ glyph_info_t gi;
+ gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;
+ gi.atlas_pos = ivec2 (v_glyph.zw) / 256;
+ return gi;
+}
+
+
+float antialias (float d)
+{
+ return smoothstep (-.75, +.75, d);
+}
+
+vec4 source_over (const vec4 src, const vec4 dst)
+{
+ // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover
+ float alpha = src.a + (dst.a * (1. - src.a));
+ return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);
+}
+
+void main()
+{
+ vec2 p = v_glyph.xy;
+ glyph_info_t gi = glyph_info_decode (v_glyph);
+
+ /* isotropic antialiasing */
+ vec2 dpdx = dFdx (p);
+ vec2 dpdy = dFdy (p);
+ float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;
+
+ vec4 color = vec4( vColor.rgb * uColor.rgb, vColor.a * uColor.a );
+
+ ivec4 uu_atlas_info = ivec4( u_atlas_info );
+ float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);
+ float sdist = gsdist / m * u_contrast;
+
+ sdist -= u_boldness * 10.;
+ if ( glyphy_iszero( u_outline ) )
+ sdist = abs (sdist) - u_outline_thickness * .5;
+ if (sdist > 1.)
+ discard;
+ float alpha = antialias (-sdist);
+ if (u_gamma_adjust != 1.)
+ alpha = pow (alpha, 1./u_gamma_adjust);
+ color = vec4 (color.rgb,color.a * alpha);
+
+ gl_FragColor = color;
+}
--- /dev/null
+uniform mediump mat4 uProjection;
+uniform mediump mat4 uModelView;
+uniform mediump mat4 uMvpMatrix;
+uniform bool uTextureMapped;
+uniform mediump vec4 uCustomTextureCoords;
+attribute highp vec2 aTexCoord;
+varying mediump vec2 vTexCoord;
+uniform mat3 uModelViewIT;
+attribute mediump vec3 aNormal;
+varying mediump vec3 vNormal;
+attribute mediump vec2 aPosition;
+varying mediump vec4 vVertex;
+attribute mediump vec4 aColor;
+varying mediump vec4 vColor;
+varying vec4 v_glyph;
+
+vec4 glyph_vertex_transcode (vec2 v)
+{
+ ivec2 g = ivec2 (v);
+ ivec2 corner = ivec2 (mod (v, 2.));
+ g /= 2;
+ ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));
+ return vec4 (corner * nominal_size, g * 4);
+}
+
+void main()
+{
+ gl_Position = uMvpMatrix * vec4 (aPosition, 0.0, 1.0);
+ v_glyph = glyph_vertex_transcode (aTexCoord);
+ vColor = aColor;
+}
\ No newline at end of file
+++ /dev/null
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw);
- vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
- mediump float minSize = min(visualSize.x, visualSize.y);
- vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
- vCornerRadius = min(vCornerRadius, minSize * 0.5);
- vRectSize = visualSize * 0.5;
- // Optimize fragment shader
- mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
- vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
- vPosition = aPosition * visualSize;
- return vec4((aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
- mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
- vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-
- gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
+++ /dev/null
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-
-vec4 ComputeVertexPosition()
-{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );
- vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
- return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
- mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
- vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-
- gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
\ No newline at end of file
+++ /dev/null
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-void main()
-{
- gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
- if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
- {
- return;
- }
- mediump float radius =
- mix(
- mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
- mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
- sign(vPosition.y) * 0.5 + 0.5
- );
-
- mediump vec2 diff = abs(vPosition) - vRectSize + radius;
- mediump float dist = length(max(diff, vec2(0.0))) - radius;
- if(dist > 1.0)
- {
- gl_FragColor = vec4(0.0);
- }
- else if(dist > -1.0)
- {
- if(min(diff.x, diff.y) < 0.0)
- {
- dist += min(diff.x, diff.y) / max(radius, 1.0);
- }
- gl_FragColor *= 1.0 - smoothstep(-1.0, 1.0, dist);
- }
-}
+++ /dev/null
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-
-void main()
-{
- gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-}
+++ /dev/null
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-void main()
-{
- gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
- if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
- {
- return;
- }
- mediump float radius =
- mix(
- mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
- mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
- sign(vPosition.y) * 0.5 + 0.5
- );
-
- mediump vec2 diff = abs(vPosition) - vRectSize + radius;
- mediump float dist = length(max(diff, vec2(0.0))) - radius;
- if(dist > 1.0)
- {
- gl_FragColor = vec4(0.0);
- }
- else if(dist > -1.0)
- {
- if(min(diff.x, diff.y) < 0.0)
- {
- dist += min(diff.x, diff.y) / max(radius, 1.0);
- }
- gl_FragColor *= 1.0 - smoothstep(-1.0, 1.0, dist);
- }
-}
+++ /dev/null
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-
-void main()
-{
- gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-}
--- /dev/null
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef RADIAL
+#define RADIAL 0
+#endif
+
+INPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform sampler2D sTexture; // sampler1D?
+uniform lowp vec4 uColor;
+uniform lowp vec3 mixColor;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+ gRadius =
+ mix(
+ mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+ mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+ sign(vPosition.y) * 0.5 + 0.5
+ );
+#endif
+}
+
+void calculatePosition()
+{
+ gFragmentPosition = abs(vPosition) - vRectSize;
+ gCenterPosition = -gRadius;
+#if IS_REQUIRED_BORDERLINE
+ gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+ gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+ gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+ gPotentialRange = 1.0;
+
+ gMaxOutlinePotential = gRadius + gPotentialRange;
+ gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if IS_REQUIRED_BORDERLINE
+ gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+ gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+ gMaxInlinePotential = gMaxOutlinePotential;
+ gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+ // reduce defect near edge of rounded corner.
+ gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+ gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+ calculateCornerRadius();
+ calculatePosition();
+ calculatePotential();
+
+ setupMinMaxPotential();
+}
+#endif
+
+
+#if IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+ mediump float potential = gPotential;
+
+ // default opacity of borderline is 0.0
+ mediump float borderlineOpacity = 0.0;
+
+ // calculate borderline opacity by potential
+ if(potential > gMinInlinePotential)
+ {
+ // potential is inside borderline range.
+ borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+ }
+
+ //calculate inside of borderline when outilneColor.a < 1.0
+ if(borderlineColor.a < 1.0)
+ {
+ mediump float tCornerRadius = -gCenterPosition;
+ mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+ mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+ if(potential > MaxTexturelinePotential)
+ {
+ // potential is out of texture range. use borderline color instead of texture
+ textureColor = vec4(borderlineColor.xyz, 0.0);
+ }
+ else if(potential > MinTexturelinePotential)
+ {
+ // potential is in texture range
+ textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+ }
+ borderlineOpacity *= borderlineColor.a;
+ }
+ return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+ mediump float potential = gPotential;
+
+ // default opacity is 1.0
+ mediump float opacity = 1.0;
+
+ // calculate borderline opacity by potential
+ if(potential > gMaxOutlinePotential)
+ {
+ // potential is out of borderline range
+ opacity = 0.0;
+ }
+ else if(potential > gMinOutlinePotential)
+ {
+ opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+ }
+ return opacity;
+}
+#endif
+
+void main()
+{
+#if RADIAL
+ lowp vec4 textureColor = TEXTURE(sTexture, vec2(length(vTexCoord), 0.5)) * vec4(mixColor, 1.0) * uColor;
+#else
+ lowp vec4 textureColor = TEXTURE(sTexture, vec2(vTexCoord.y, 0.5)) * vec4(mixColor, 1.0) * uColor;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ // skip most potential calculate for performance
+ if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+ {
+ OUT_COLOR = textureColor;
+ return;
+ }
+ PreprocessPotential();
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+ textureColor = convertBorderlineColor(textureColor);
+#endif
+ OUT_COLOR = textureColor;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+ mediump float opacity = calculateCornerOpacity();
+ OUT_COLOR *= opacity;
+#endif
+}
--- /dev/null
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef USER_SPACE
+#define USER_SPACE 0
+#endif
+
+INPUT mediump vec2 aPosition;
+OUTPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform highp mat4 uMvpMatrix;
+uniform highp vec3 uSize;
+uniform mediump mat3 uAlignmentMatrix;
+
+//Visual size and offset
+uniform mediump vec2 offset;
+uniform highp vec2 size;
+uniform mediump vec4 offsetSizeMode;
+uniform mediump vec2 origin;
+uniform mediump vec2 anchorPoint;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
+
+vec4 ComputeVertexPosition()
+{
+ vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );
+ vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ vRectSize = visualSize * 0.5;
+ vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if IS_REQUIRED_BORDERLINE
+ mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+ mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+ vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+ vCornerRadius = min(vCornerRadius, minSize * 0.5);
+ // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+ mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+ vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+ vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+ vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+ vPosition = aPosition * visualSize;
+#else
+ mediump vec2 vPosition = aPosition * visualSize;
+#endif
+
+ return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
+}
+
+void main()
+{
+ mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
+ gl_Position = uMvpMatrix * ComputeVertexPosition();
+#if USER_SPACE
+ vertexPosition.xyz *= uSize;
+#endif
+ vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
+}
+++ /dev/null
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw);
- vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
- mediump float minSize = min(visualSize.x, visualSize.y);
- vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
- vCornerRadius = min(vCornerRadius, minSize * 0.5);
- vRectSize = visualSize * 0.5;
- // Optimze fragment shader
- mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
- vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
- vCornerRadius = max(vCornerRadius, 1.0);
- vPosition = aPosition * visualSize;
- return vec4((aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
- mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
- vertexPosition.xyz *= uSize;
- gl_Position = uMvpMatrix * ComputeVertexPosition();
-
- vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-}
+++ /dev/null
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-
-vec4 ComputeVertexPosition()
-{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );
- vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
- return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
- mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
- vertexPosition.xyz *= uSize;
- gl_Position = uMvpMatrix * ComputeVertexPosition();
-
- vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-}
+++ /dev/null
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform mediump vec4 uAtlasRect;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
- mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );
- OUT_COLOR = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
-}
\ No newline at end of file
+++ /dev/null
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform mediump vec4 uAtlasRect;
-
-// WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
-uniform lowp vec2 wrapMode;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
-
-{
- mediump float coord;
- if( wrap > 1.5 )\n // REFLECT
- coord = 1.0-abs(fract(coordinate*0.5)*2.0 - 1.0);
- else \n// warp == 0 or 1
- coord = mix(coordinate, fract( coordinate ), wrap);
- return clamp( mix(range.x, range.y, coord), range.x, range.y );
-}
-
-void main()
-{
- mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
- wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );
- OUT_COLOR = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
-}
\ No newline at end of file
+++ /dev/null
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
- OUT_COLOR = TEXTURE( sTexture, vTexCoord ) * uColor * vec4( mixColor, 1.0 );
-}
+++ /dev/null
-INPUT mediump vec2 vTexCoord;
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform sampler2D sTexture;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
- if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
- {
- OUT_COLOR = TEXTURE(sTexture, vTexCoord) * uColor * vec4(mixColor, 1.0);
- return;
- }
- mediump float radius =
- mix(
- mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
- mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
- sign(vPosition.y) * 0.5 + 0.5
- );
-
- mediump vec2 diff = abs(vPosition) - vRectSize + radius;
- mediump float dist = length(max(diff, vec2(0.0))) - radius;
- mediump float opacity = 1.0;
- if(dist > 1.0)
- {
- opacity = 0.0;
- }
- else if(dist > -1.0)
- {
- if(min(diff.x, diff.y) < 0.0)
- {
- dist += min(diff.x, diff.y) / max(radius, 1.0);
- }
- opacity = 1.0 - smoothstep(-1.0, 1.0, dist);
- }
-
- OUT_COLOR = TEXTURE(sTexture, vTexCoord) * uColor * vec4(mixColor, 1.0);
- OUT_COLOR.a *= opacity;
- OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
-}
+++ /dev/null
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vTexCoord;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump vec4 pixelArea;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-uniform mediump vec2 extraSize;
-
-vec4 ComputeVertexPosition()
-{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw) + extraSize;
- vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
- mediump float minSize = min(visualSize.x, visualSize.y);
- vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
- vCornerRadius = min(vCornerRadius, minSize * 0.5);
- vRectSize = visualSize * 0.5;
- // Optimize fragment shader
- mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
- vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
- vPosition = aPosition* visualSize;
- return vec4(vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
- gl_Position = uMvpMatrix * ComputeVertexPosition();
- vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5));
-}
--- /dev/null
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef ATLAS_DEFAULT_WARP
+#define ATLAS_DEFAULT_WARP 0
+#endif
+#ifndef ATLAS_CUSTOM_WARP
+#define ATLAS_CUSTOM_WARP 0
+#endif
+
+INPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform sampler2D sTexture;
+#if ATLAS_DEFAULT_WARP
+uniform mediump vec4 uAtlasRect;
+#elif ATLAS_CUSTOM_WARP
+// WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
+uniform lowp vec2 wrapMode;
+#endif
+
+uniform lowp vec4 uColor;
+uniform lowp vec3 mixColor;
+uniform lowp float preMultipliedAlpha;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+
+#if ATLAS_CUSTOM_WARP
+mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
+{
+ mediump float coord;
+ if( wrap > 1.5 ) /* REFLECT */
+ coord = 1.0 - abs(fract(coordinate*0.5)*2.0 - 1.0);
+ else /* warp is 0 or 1 */
+ coord = mix(coordinate, fract(coordinate), wrap);
+ return clamp(mix(range.x, range.y, coord), range.x, range.y);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+ gRadius =
+ mix(
+ mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+ mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+ sign(vPosition.y) * 0.5 + 0.5
+ );
+#endif
+}
+
+void calculatePosition()
+{
+ gFragmentPosition = abs(vPosition) - vRectSize;
+ gCenterPosition = -gRadius;
+#if IS_REQUIRED_BORDERLINE
+ gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+ gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+ gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+ gPotentialRange = 1.0;
+
+ gMaxOutlinePotential = gRadius + gPotentialRange;
+ gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if IS_REQUIRED_BORDERLINE
+ gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+ gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+ gMaxInlinePotential = gMaxOutlinePotential;
+ gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+ // reduce defect near edge of rounded corner.
+ gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+ gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+ calculateCornerRadius();
+ calculatePosition();
+ calculatePotential();
+
+ setupMinMaxPotential();
+}
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+ mediump float potential = gPotential;
+
+ // default opacity of borderline is 0.0
+ mediump float borderlineOpacity = 0.0;
+
+ // calculate borderline opacity by potential
+ if(potential > gMinInlinePotential)
+ {
+ // potential is inside borderline range.
+ borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+ }
+
+ //calculate inside of borderline when outilneColor.a < 1.0
+ if(borderlineColor.a < 1.0)
+ {
+ mediump float tCornerRadius = -gCenterPosition;
+ mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+ mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+ if(potential > MaxTexturelinePotential)
+ {
+ // potential is out of texture range. use borderline color instead of texture
+ textureColor = vec4(borderlineColor.xyz, 0.0);
+ }
+ else if(potential > MinTexturelinePotential)
+ {
+ // potential is in texture range
+ textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+ }
+ borderlineOpacity *= borderlineColor.a;
+ }
+ return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+ mediump float potential = gPotential;
+
+ // default opacity is 1.0
+ mediump float opacity = 1.0;
+
+ // calculate borderline opacity by potential
+ if(potential > gMaxOutlinePotential)
+ {
+ // potential is out of borderline range
+ opacity = 0.0;
+ }
+ else if(potential > gMinOutlinePotential)
+ {
+ opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+ }
+ return opacity;
+}
+#endif
+
+void main()
+{
+#if ATLAS_DEFAULT_WARP
+ mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );
+#elif ATLAS_CUSTOM_WARP
+ mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
+ wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );
+#else
+ mediump vec2 texCoord = vTexCoord;
+#endif
+
+ lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ // skip most potential calculate for performance
+ if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+ {
+ OUT_COLOR = textureColor;
+ return;
+ }
+ PreprocessPotential();
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+ textureColor = convertBorderlineColor(textureColor);
+#endif
+ OUT_COLOR = textureColor;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+ mediump float opacity = calculateCornerOpacity();
+ OUT_COLOR.a *= opacity;
+ OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
+#endif
+}
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+
INPUT mediump vec2 aPosition;
OUTPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
uniform highp mat4 uMvpMatrix;
uniform highp vec3 uSize;
uniform mediump vec4 offsetSizeMode;
uniform mediump vec2 origin;
uniform mediump vec2 anchorPoint;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
uniform mediump vec2 extraSize;
vec4 ComputeVertexPosition()
{
- vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
- vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
- return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+ vec2 visualSize = mix(uSize.xy * size, size, offsetSizeMode.zw) + extraSize;
+ vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ vRectSize = visualSize * 0.5;
+ vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if IS_REQUIRED_BORDERLINE
+ mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+ mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+ vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+ vCornerRadius = min(vCornerRadius, minSize * 0.5);
+ // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+ mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+ vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+ vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+ vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+ vPosition = aPosition * visualSize;
+#else
+ mediump vec2 vPosition = aPosition * visualSize;
+#endif
+
+ vTexCoord = pixelArea.xy + pixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5));
+ return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
}
void main()
{
gl_Position = uMvpMatrix * ComputeVertexPosition();
- vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );
-}
\ No newline at end of file
+}
--- /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/text/hyphenator.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/hyphenation.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+
+#include <cstring> // for strcmp
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+const char* UTF8 = "UTF-8";
+
+Vector<bool> GetWordHyphens(const Character* word,
+ Length wordSize,
+ const char* lang)
+{
+ Vector<bool> hyphens;
+
+ if(0u == wordSize || word == nullptr)
+ {
+ // Nothing to do if there are no characters.
+ return hyphens;
+ }
+
+ TextAbstraction::Hyphenation hyphenation = TextAbstraction::Hyphenation::Get();
+
+ // first get the needed encoding
+ std::string text;
+ if(strcmp(hyphenation.GetDictionaryEncoding(lang), UTF8) == 0)
+ {
+ Utf32ToUtf8(word, wordSize, text);
+ }
+ else
+ {
+ text = std::string((char*)word, (size_t)(wordSize * sizeof(Character)));
+ }
+
+ return hyphenation.GetWordHyphens(text.c_str(), (int)text.length(), lang);
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_HYPHENATOR_H
+#define DALI_TOOLKIT_TEXT_HYPHENATOR_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/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * Gets a vector booleans that indicates possible hyphen locations.
+ *
+ * @param[in] word the word to get possible hyphens for.
+ * @param[in] wordSize the word size in bytes.
+ * @param[in] lang the language for the word
+ *
+ * @return vector of boolean, true if possible to hyphenate at this character position.
+ */
+Vector<bool> GetWordHyphens(const Character* word,
+ Length wordSize,
+ const char* lang);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_HYPHENATOR_H
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
#endif
-const float MAX_FLOAT = std::numeric_limits<float>::max();
-const CharacterDirection LTR = false;
-const CharacterDirection RTL = !LTR;
-const float LINE_SPACING = 0.f;
-const float MIN_LINE_SIZE = 0.f;
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+const CharacterDirection LTR = false;
+const CharacterDirection RTL = !LTR;
+const float LINE_SPACING = 0.f;
+const float MIN_LINE_SIZE = 0.f;
+const Character HYPHEN_UNICODE = 0x002D;
inline bool isEmptyLineAtLast(const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line)
{
const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
const bool isMultiline = mLayout == MULTI_LINE_BOX;
- const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD;
+ const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD ||
+ (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED);
+ const bool isHyphenMode = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION;
+ const bool isMixedMode = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED;
// The last glyph to be laid-out.
const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
FontId lastFontId = glyphMetrics.fontId;
UpdateLineHeight(glyphMetrics, tmpLineLayout);
- bool oneWordLaidOut = false;
+ bool oneWordLaidOut = false;
+ bool oneHyphenLaidOut = false;
+ GlyphIndex hyphenIndex = 0;
+ GlyphInfo hyphenGlyph;
for(GlyphIndex glyphIndex = lineLayout.glyphIndex;
glyphIndex < lastGlyphOfParagraphPlusOne;)
(tmpLineLayout.length > parameters.boundingBox.width))
{
// Current word does not fit in the box's width.
- if(!oneWordLaidOut || completelyFill)
+ if(((oneHyphenLaidOut && isHyphenMode) ||
+ (!oneWordLaidOut && isMixedMode && oneHyphenLaidOut)) &&
+ !completelyFill)
+ {
+ parameters.textModel->mVisualModel->mHyphen.glyph.PushBack(hyphenGlyph);
+ parameters.textModel->mVisualModel->mHyphen.index.PushBack(hyphenIndex + 1);
+ }
+
+ if((!oneWordLaidOut && !oneHyphenLaidOut) || completelyFill)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " Break the word by character\n");
(TextAbstraction::LINE_MUST_BREAK == lineBreakInfo))
{
LineLayout currentLineLayout = lineLayout;
-
+ oneHyphenLaidOut = false;
// Must break the line. Update the line layout and return.
MergeLineLayout(lineLayout, tmpLineLayout);
if(isMultiline &&
(TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo))
{
- oneWordLaidOut = isWordLaidOut;
+ oneHyphenLaidOut = false;
+ oneWordLaidOut = isWordLaidOut;
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " One word laid-out\n");
// Current glyph is the last one of the current word.
tmpLineLayout.Clear();
}
+ if(isMultiline &&
+ ((isHyphenMode || (!oneWordLaidOut && isMixedMode))) &&
+ (TextAbstraction::LINE_HYPHENATION_BREAK == lineBreakInfo))
+ {
+ hyphenGlyph = GlyphInfo();
+ hyphenGlyph.fontId = glyphsBuffer[glyphIndex].fontId;
+
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ hyphenGlyph.index = fontClient.GetGlyphIndex(hyphenGlyph.fontId, HYPHEN_UNICODE);
+
+ mMetrics->GetGlyphMetrics(&hyphenGlyph, 1);
+
+ if((tmpLineLayout.length + hyphenGlyph.width) <= parameters.boundingBox.width)
+ {
+ hyphenIndex = glyphIndex;
+ oneHyphenLaidOut = true;
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, " One hyphen laid-out\n");
+
+ // Current glyph is the last one of the current word hyphen.
+ // Add the temporal layout to the current one.
+ MergeLineLayout(lineLayout, tmpLineLayout);
+
+ tmpLineLayout.Clear();
+ }
+ }
+
glyphIndex += numberOfGLyphsInGroup;
}
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height);
+ layoutParameters.textModel->mVisualModel->mHyphen.glyph.Clear();
+ layoutParameters.textModel->mVisualModel->mHyphen.index.Clear();
+
Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
if(0u == layoutParameters.numberOfGlyphs)
if(ellipsis)
{
+ //clear hyphen from ellipsis line
+ const Length* hyphenIndices = layoutParameters.textModel->mVisualModel->mHyphen.index.Begin();
+ Length hyphensCount = layoutParameters.textModel->mVisualModel->mHyphen.glyph.Size();
+
+ while(hyphenIndices && hyphensCount > 0 && hyphenIndices[hyphensCount - 1] >= layout.glyphIndex)
+ {
+ layoutParameters.textModel->mVisualModel->mHyphen.index.Remove(layoutParameters.textModel->mVisualModel->mHyphen.index.Begin() + hyphensCount - 1);
+ layoutParameters.textModel->mVisualModel->mHyphen.glyph.Remove(layoutParameters.textModel->mVisualModel->mHyphen.glyph.Begin() + hyphensCount - 1);
+ hyphensCount--;
+ }
+
// No more lines to layout.
break;
}
mColorRuns,
removedColorRuns);
+ // This is needed until now for underline tag in mark-up processor
+ // Process the underlined runs.
+ Vector<UnderlinedCharacterRun> removedUnderlinedCharacterRuns;
+ UpdateCharacterRuns<UnderlinedCharacterRun>(index,
+ numberOfCharacters,
+ totalNumberOfCharacters,
+ mUnderlinedCharacterRuns,
+ removedUnderlinedCharacterRuns);
+
// Process the background color runs.
Vector<ColorRun> removedBackgroundColorRuns;
UpdateCharacterRuns<ColorRun>(index,
#include <dali-toolkit/internal/text/font-run.h>
#include <dali-toolkit/internal/text/paragraph-run.h>
#include <dali-toolkit/internal/text/script-run.h>
+#include <dali-toolkit/internal/text/underlined-character-run.h>
namespace Dali
{
Vector<BidirectionalLineInfoRun> mBidirectionalLineInfo;
Vector<EmbeddedItem> mEmbeddedItems;
Vector<Anchor> mAnchors;
+ Vector<UnderlinedCharacterRun> mUnderlinedCharacterRuns; ///< The underlined character run from markup-processor
BidirectionalLineRunIndex mBidirectionalLineIndex; ///< The last fetched bidirectional line info.
};
}
/**
+ * @brief Initializes a underlined character run to its defaults.
+ *
+ * @param[in,out] underlinedCharacterRun The underelined character run to initialize.
+ */
+void Initialize(UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ underlinedCharacterRun.characterRun.characterIndex = 0u;
+ underlinedCharacterRun.characterRun.numberOfCharacters = 0u;
+}
+
+/**
* @brief Splits the tag string into the tag name and its attributes.
*
* The attributes are stored in a vector in the tag.
}
/**
- * @brief Processes a particular tag for the required run (color-run or font-run).
+ * @brief Processes a particular tag for the required run (color-run, font-run or underlined-character-run).
*
- * @tparam RunType Whether ColorRun or FontDescriptionRun
+ * @tparam RunType Whether ColorRun , FontDescriptionRun or UnderlinedCharacterRun
*
* @param[in/out] runsContainer The container containing all the runs
* @param[in/out] styleStack The style stack
* @param[in/out] markupProcessData The markup process data
* @param[in] fontRunIndex The font run index
* @param[in] colorRunIndex The color run index
+ * @param[in] underlinedCharacterRunIndex The underlined character run index
*/
-void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex)
+void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex, const StyleStack::RunIndex underlinedCharacterRunIndex)
{
markupProcessData.fontRuns.Resize(fontRunIndex);
markupProcessData.colorRuns.Resize(colorRunIndex);
+ markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
#ifdef DEBUG_ENABLED
for(unsigned int i = 0; i < colorRunIndex; ++i)
StyleStack styleStack;
// Points the next free position in the vector of runs.
- StyleStack::RunIndex colorRunIndex = 0u;
- StyleStack::RunIndex fontRunIndex = 0u;
+ StyleStack::RunIndex colorRunIndex = 0u;
+ StyleStack::RunIndex fontRunIndex = 0u;
+ StyleStack::RunIndex underlinedCharacterRunIndex = 0u;
// check tag reference
int colorTagReference = 0u;
int fontTagReference = 0u;
int iTagReference = 0u;
int bTagReference = 0u;
+ int uTagReference = 0u;
// Give an initial default value to the model's vectors.
markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
+ markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
// Get the mark-up string buffer.
const char* markupStringBuffer = markupString.c_str();
} // <i></i>
else if(TokenComparison(XHTML_U_TAG, tag.buffer, tag.length))
{
- // TODO: If !tag.isEndTag, then create a new underline run.
- // else Pop the top of the stack and set the number of characters of the run.
- } // <u></u>
+ ProcessTagForRun<UnderlinedCharacterRun>(
+ markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { });
+ } // <u></u>
else if(TokenComparison(XHTML_B_TAG, tag.buffer, tag.length))
{
ProcessTagForRun<FontDescriptionRun>(
}
// Resize the model's vectors.
- ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex);
+ ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex);
}
} // namespace Text
#include <dali-toolkit/internal/text/color-run.h>
#include <dali-toolkit/internal/text/embedded-item.h>
#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/underlined-character-run.h>
namespace Dali
{
MarkupProcessData(Vector<ColorRun>& colorRuns,
Vector<FontDescriptionRun>& fontRuns,
Vector<EmbeddedItem>& items,
- Vector<Anchor>& anchors)
+ Vector<Anchor>& anchors,
+ Vector<UnderlinedCharacterRun>& underlinedCharacterRuns)
: colorRuns(colorRuns),
fontRuns(fontRuns),
items(items),
anchors(anchors),
+ underlinedCharacterRuns(underlinedCharacterRuns),
markupProcessedText()
{
}
- Vector<ColorRun>& colorRuns; ///< The color runs.
- Vector<FontDescriptionRun>& fontRuns; ///< The font description runs.
- Vector<EmbeddedItem>& items; ///< The embedded items.
- Vector<Anchor>& anchors; ///< The anchors.
- std::string markupProcessedText; ///< The mark-up string.
+ Vector<ColorRun>& colorRuns; ///< The color runs.
+ Vector<FontDescriptionRun>& fontRuns; ///< The font description runs.
+ Vector<EmbeddedItem>& items; ///< The embedded items.
+ Vector<Anchor>& anchors; ///< The anchors.
+ Vector<UnderlinedCharacterRun>& underlinedCharacterRuns; ///< The underlined character runs.
+ std::string markupProcessedText; ///< The mark-up string.
};
/**
const float ZERO(0.0f);
const float HALF(0.5f);
const float ONE(1.0f);
-const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
-const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
-const uint32_t MAX_ATLAS_WIDTH = 1024u;
-const uint32_t MAX_ATLAS_HEIGHT = 1024u;
const uint32_t DOUBLE_PIXEL_PADDING = 4u;//Padding will be added twice to Atlas
const uint16_t NO_OUTLINE = 0u;
} // namespace
mRight(0.0f),
mUnderlinePosition(0.0f),
mUnderlineThickness(0.0f),
- mMeshRecordIndex(0u)
+ mMeshRecordIndex(0u),
+ mUnderlineChunkId(0u)
{
}
float mUnderlinePosition;
float mUnderlineThickness;
uint32_t mMeshRecordIndex;
+ uint32_t mUnderlineChunkId;
};
struct MaxBlockSize
void CacheGlyph(const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot)
{
+ const Size& defaultTextAtlasSize = mFontClient.GetDefaultTextAtlasSize(); //Retrieve default size of text-atlas-block from font-client.
+ const Size& maximumTextAtlasSize = mFontClient.GetMaximumTextAtlasSize(); //Retrieve maximum size of text-atlas-block from font-client.
+
const bool glyphNotCached = !mGlyphManager.IsCached(glyph.fontId, glyph.index, style, slot); // Check FontGlyphRecord vector for entry with glyph index and fontId
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached) ? "not cached" : "cached");
// If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas
// Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice.
- uint32_t default_width = DEFAULT_ATLAS_WIDTH;
- uint32_t default_height = DEFAULT_ATLAS_HEIGHT;
+ uint32_t default_width = defaultTextAtlasSize.width;
+ uint32_t default_height = defaultTextAtlasSize.height;
while (
(blockSize.mNeededBlockWidth >= (default_width - (DOUBLE_PIXEL_PADDING + 1u)) ||
blockSize.mNeededBlockHeight >= (default_height - (DOUBLE_PIXEL_PADDING + 1u)))
&&
- (default_width < MAX_ATLAS_WIDTH &&
- default_height < MAX_ATLAS_HEIGHT))
+ (default_width < maximumTextAtlasSize.width &&
+ default_height < maximumTextAtlasSize.height))
{
default_width <<= 1u;
default_height <<= 1u;
float currentUnderlineThickness,
std::vector<MeshRecord>& meshContainer,
Vector<TextCacheEntry>& newTextCache,
- Vector<Extent>& extents)
+ Vector<Extent>& extents,
+ uint32_t underlineChunkId)
{
// Generate mesh data for this quad, plugging in our supplied position
AtlasManager::Mesh2D newMesh;
underlineGlyph,
currentUnderlinePosition,
currentUnderlineThickness,
- slot);
+ slot,
+ underlineChunkId);
}
void CreateActors(const std::vector<MeshRecord>& meshContainer,
Vector<Extent> extents;
mDepth = depth;
- const Vector2& textSize(view.GetLayoutSize());
- const Vector2 halfTextSize(textSize * 0.5f);
- const Vector2& shadowOffset(view.GetShadowOffset());
- const Vector4& shadowColor(view.GetShadowColor());
- const bool underlineEnabled = view.IsUnderlineEnabled();
- const Vector4& underlineColor(view.GetUnderlineColor());
- const float underlineHeight = view.GetUnderlineHeight();
- const uint16_t outlineWidth = view.GetOutlineWidth();
- const Vector4& outlineColor(view.GetOutlineColor());
- const bool isOutline = 0u != outlineWidth;
+ const Vector2& textSize(view.GetLayoutSize());
+ const Vector2 halfTextSize(textSize * 0.5f);
+ const Vector2& shadowOffset(view.GetShadowOffset());
+ const Vector4& shadowColor(view.GetShadowColor());
+ const bool underlineEnabled = view.IsUnderlineEnabled();
+ const Vector4& underlineColor(view.GetUnderlineColor());
+ const float underlineHeight = view.GetUnderlineHeight();
+ const uint16_t outlineWidth = view.GetOutlineWidth();
+ const Vector4& outlineColor(view.GetOutlineColor());
+ const bool isOutline = 0u != outlineWidth;
+ const GlyphInfo* hyphens = view.GetHyphens();
+ const Length* hyphenIndices = view.GetHyphenIndices();
+ const Length hyphensCount = view.GetHyphensCount();
const bool useDefaultColor = (NULL == colorsBuffer);
const GlyphInfo* const glyphsBuffer = glyphs.Begin();
const Vector2* const positionsBuffer = positions.Begin();
const Vector2 lineOffsetPosition(minLineOffset, 0.f);
+ uint32_t hyphenIndex = 0;
+
+ //For septated underlined chunks. (this is for Markup case)
+ uint32_t underlineChunkId = 0u; // give id for each chunk.
+ bool isPreUnderlined = false; // status of underlined for previous glyph.
for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
{
- const GlyphInfo& glyph = *(glyphsBuffer + i);
- const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns);
- thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined;
+ GlyphInfo glyph;
+ bool addHyphen = ((hyphenIndex < hyphensCount) && hyphenIndices && (i == hyphenIndices[hyphenIndex]));
+ if(addHyphen && hyphens)
+ {
+ glyph = hyphens[hyphenIndex];
+ i--;
+ }
+ else
+ {
+ glyph = *(glyphsBuffer + i);
+ }
+
+ const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns);
+ thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined;
// No operation for white space
if(glyph.width && glyph.height)
}
lastUnderlinedFontId = glyph.fontId;
+
} // underline
AtlasGlyphManager::GlyphStyle style;
}
// Move the origin (0,0) of the mesh to the center of the actor
- const Vector2& temp = *(positionsBuffer + i);
- const Vector2 position = Vector2(roundf(temp.x), temp.y) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues.
+ Vector2 position = *(positionsBuffer + i);
+
+ if(addHyphen)
+ {
+ GlyphInfo tempInfo = *(glyphsBuffer + i);
+ position.x = position.x + tempInfo.advance - tempInfo.xBearing + glyph.xBearing;
+ position.y += tempInfo.yBearing - glyph.yBearing;
+ }
+
+ position = Vector2(roundf(position.x), position.y) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues.
if(0u != slot.mImageId) // invalid slot id, glyph has failed to be added to atlas
{
currentUnderlineThickness,
meshContainer,
newTextCache,
- extents);
+ extents,
+ underlineChunkId);
lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId.
}
currentUnderlineThickness,
meshContainerOutline,
newTextCache,
- extents);
+ extents,
+ 0u);
}
+
+
+ //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case)
+ // Examples: "Hello <u>World</u> Hello <u>World</u>", "<u>World</u> Hello <u>World</u>", "<u> World</u> Hello <u>World</u>"
+ if( isPreUnderlined && (isPreUnderlined != isGlyphUnderlined))
+ {
+ underlineChunkId++;
+ }
+ //Keep status of underlined for previous glyph to check consecutive indices
+ isPreUnderlined = isGlyphUnderlined;
+ }
+
+ if(addHyphen)
+ {
+ hyphenIndex++;
}
} // glyphs
bool underlineGlyph,
float underlinePosition,
float underlineThickness,
- AtlasManager::AtlasSlot& slot)
+ AtlasManager::AtlasSlot& slot,
+ uint32_t underlineChunkId)
{
if(slot.mImageId)
{
right,
baseLine,
underlinePosition,
- underlineThickness);
+ underlineThickness,
+ underlineChunkId);
}
return;
right,
baseLine,
underlinePosition,
- underlineThickness);
+ underlineThickness,
+ underlineChunkId);
}
}
}
float right,
float baseLine,
float underlinePosition,
- float underlineThickness)
+ float underlineThickness,
+ uint32_t underlineChunkId)
{
bool foundExtent = false;
for(Vector<Extent>::Iterator eIt = extents.Begin(),
eIt != eEndIt;
++eIt)
{
- if(Equals(baseLine, eIt->mBaseLine))
+ if(Equals(baseLine, eIt->mBaseLine) && underlineChunkId == eIt->mUnderlineChunkId)
{
foundExtent = true;
if(left < eIt->mLeft)
extent.mUnderlinePosition = underlinePosition;
extent.mUnderlineThickness = underlineThickness;
extent.mMeshRecordIndex = index;
+ extent.mUnderlineChunkId = underlineChunkId;
extents.PushBack(extent);
}
}
// Combine the two buffers
imageBuffer = CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight);
}
+
+ // Markup-Processor
+
+ imageBuffer = ApplyMarkupProcessorOnPixelBuffer(imageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, penX, penY);
}
// Create the final PixelData for the combined image buffer
const Vector2* const positionBuffer = mModel->GetLayout();
const Vector4* const colorsBuffer = mModel->GetColors();
const ColorIndex* const colorIndexBuffer = mModel->GetColorIndices();
+ const GlyphInfo* hyphens = mModel->GetHyphens();
+ const Length* hyphenIndices = mModel->GetHyphenIndices();
+ const Length hyphensCount = mModel->GetHyphensCount();
// Whether to use the default color.
const bool useDefaultColor = (NULL == colorsBuffer);
}
// Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
- TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ Length hyphenIndex = 0;
// Traverses the lines of the text.
for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
float lineExtentLeft = bufferWidth;
float lineExtentRight = 0.0f;
float baseline = 0.0f;
+ bool addHyphen = false;
// Traverses the glyphs of the line.
const GlyphIndex endGlyphIndex = std::min(numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs);
}
// Retrieve the glyph's info.
- const GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
+ const GlyphInfo* glyphInfo;
+
+ if(addHyphen && hyphens)
+ {
+ glyphInfo = hyphens + hyphenIndex;
+ hyphenIndex++;
+ }
+ else
+ {
+ glyphInfo = glyphsBuffer + glyphIndex;
+ }
if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
(glyphInfo->height < Math::MACHINE_EPSILON_1000))
} // underline
// Retrieves the glyph's position.
- const Vector2* const position = positionBuffer + glyphIndex;
- if(baseline < position->y + glyphInfo->yBearing)
+ Vector2 position = *(positionBuffer + glyphIndex);
+
+ if(addHyphen)
+ {
+ GlyphInfo tempInfo = *(glyphsBuffer + glyphIndex);
+ position.x = position.x + tempInfo.advance - tempInfo.xBearing + glyphInfo->xBearing;
+ position.y = -glyphInfo->yBearing;
+ }
+
+ if(baseline < position.y + glyphInfo->yBearing)
{
- baseline = position->y + glyphInfo->yBearing;
+ baseline = position.y + glyphInfo->yBearing;
}
// Calculate the positions of leftmost and rightmost glyphs in the current line
- if(position->x < lineExtentLeft)
+ if(position.x < lineExtentLeft)
{
- lineExtentLeft = position->x;
+ lineExtentLeft = position.x;
}
- if(position->x + glyphInfo->width > lineExtentRight)
+ if(position.x + glyphInfo->width > lineExtentRight)
{
- lineExtentRight = position->x + glyphInfo->width;
+ lineExtentRight = position.x + glyphInfo->width;
}
// Retrieves the glyph's color.
// Set the buffer of the glyph's bitmap into the final bitmap's buffer
TypesetGlyph(glyphData,
- position,
+ &position,
&color,
style,
pixelFormat);
delete[] glyphData.glyphBitmap.buffer;
glyphData.glyphBitmap.buffer = NULL;
}
+
+ if(hyphenIndices)
+ {
+ while((hyphenIndex < hyphensCount) && (glyphIndex > hyphenIndices[hyphenIndex]))
+ {
+ hyphenIndex++;
+ }
+
+ addHyphen = ((hyphenIndex < hyphensCount) && ((glyphIndex + 1) == hyphenIndices[hyphenIndex]));
+ if(addHyphen)
+ {
+ glyphIndex--;
+ }
+ }
}
// Draw the underline from the leftmost glyph to the rightmost glyph
return combinedPixelBuffer;
}
+Devel::PixelBuffer Typesetter::ApplyMarkupProcessorOnPixelBuffer(Devel::PixelBuffer topPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset)
+{
+ // Apply the markup-Processor if enabled
+ const bool markupProcessorEnabled = mModel->IsMarkupProcessorEnabled();
+ if(markupProcessorEnabled)
+ {
+ // Underline-tags (this is for Markup case)
+ // Get the underline runs.
+ const Length numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
+ Vector<GlyphRun> underlineRuns;
+ underlineRuns.Resize(numberOfUnderlineRuns);
+ mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+ // Iterate on the consecutive underlined glyph run and connect them into one chunk of underlined characters.
+ Vector<GlyphRun>::ConstIterator itGlyphRun = underlineRuns.Begin();
+ Vector<GlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
+ GlyphIndex startGlyphIndex, endGlyphIndex;
+
+ //The outer loop to iterate on the separated chunks of underlined glyph runs
+ while(itGlyphRun != endItGlyphRun)
+ {
+ startGlyphIndex = itGlyphRun->glyphIndex;
+ endGlyphIndex = startGlyphIndex;
+ //The inner loop to make a connected underline for the consecutive characters
+ do
+ {
+ endGlyphIndex += itGlyphRun->numberOfGlyphs;
+ itGlyphRun++;
+ } while(itGlyphRun != endItGlyphRun && itGlyphRun->glyphIndex == endGlyphIndex);
+
+ endGlyphIndex--;
+
+ // Create the image buffer for underline
+ Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
+ // Combine the two buffers
+ topPixelBuffer = CombineImageBuffer(topPixelBuffer, underlineImageBuffer, bufferWidth, bufferHeight);
+ }
+ }
+
+ return topPixelBuffer;
+}
+
Typesetter::Typesetter(const ModelInterface* const model)
: mModel(new ViewModel(model))
{
*/
Devel::PixelBuffer CombineImageBuffer(Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeightbool);
+ /**
+ * @brief Apply behaviour of tags if the markup-processor is enabled.
+ *
+ * The properties on TextLabel override the behavior of Markup.
+ * Because the markup will be the bottom layer buffer
+ * - i.e: If you set property UNDERLINE to enabled and blue.
+ * And the TEXT is "<color value='green'>Hello</color> <u>World</u> <i>Hello</i> <b>World</b>".
+ * Then the output of the whole text is underlined by blue line.
+ *
+ * @param[in] topPixelBuffer The top layer buffer.
+ * @param[in] bufferWidth The width of the image buffer.
+ * @param[in] bufferHeight The height of the image buffer.
+ * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment, not ignored by default.
+ * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+ * @param[in] horizontalOffset The horizontal offset to be added to the glyph's position.
+ * @param[in] verticalOffset The vertical offset to be added to the glyph's position.
+ *
+ * @return The image buffer with the markup.
+ */
+ Devel::PixelBuffer ApplyMarkupProcessorOnPixelBuffer(Devel::PixelBuffer topPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset);
+
protected:
/**
* @brief A reference counted object may only be deleted by calling Unreference().
+++ /dev/null
-static const char* glyphy_common_glsl =
- "/*\n"
- " * Copyright 2012 Google, Inc. All Rights Reserved.\n"
- " *\n"
- " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
- " * you may not use this file except in compliance with the License.\n"
- " * You may obtain a copy of the License at\n"
- " *\n"
- " * http://www.apache.org/licenses/LICENSE-2.0\n"
- " *\n"
- " * Unless required by applicable law or agreed to in writing, software\n"
- " * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
- " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
- " * See the License for the specific language governing permissions and\n"
- " * limitations under the License.\n"
- " *\n"
- " * Google Author(s): Behdad Esfahbod, Maysum Panju\n"
- " */\n"
- "\n"
- "\n"
- "#ifndef GLYPHY_INFINITY\n"
- "# define GLYPHY_INFINITY 1e9\n"
- "#endif\n"
- "#ifndef GLYPHY_EPSILON\n"
- "# define GLYPHY_EPSILON 1e-5\n"
- "#endif\n"
- "\n"
- "#ifndef GLYPHY_RGBA\n"
- "# ifdef GLYPHY_BGRA\n"
- "# define GLYPHY_RGBA(v) glyphy_bgra (v)\n"
- "# else\n"
- "# define GLYPHY_RGBA(v) glyphy_rgba (v)\n"
- "# endif\n"
- "#endif\n"
- "\n"
- "vec4\n"
- "glyphy_rgba (const vec4 v)\n"
- "{\n"
- " return v.rgba;\n"
- "}\n"
- "\n"
- "vec4\n"
- "glyphy_bgra (const vec4 v)\n"
- "{\n"
- " return v.bgra;\n"
- "}\n"
- "\n"
- "\n"
- "struct glyphy_arc_t {\n"
- " vec2 p0;\n"
- " vec2 p1;\n"
- " float d;\n"
- "};\n"
- "\n"
- "struct glyphy_arc_endpoint_t {\n"
- " /* Second arc endpoint */\n"
- " vec2 p;\n"
- " /* Infinity if this endpoint does not form an arc with the previous\n"
- " * endpoint. Ie. a \"move_to\". Test with glyphy_isinf().\n"
- " * Arc depth otherwise. */\n"
- " float d;\n"
- "};\n"
- "\n"
- "struct glyphy_arc_list_t {\n"
- " /* Number of endpoints in the list.\n"
- " * Will be zero if we're far away inside or outside, in which case side is set.\n"
- " * Will be -1 if this arc-list encodes a single line, in which case line_* are set. */\n"
- " int num_endpoints;\n"
- "\n"
- " /* If num_endpoints is zero, this specifies whether we are inside (-1)\n"
- " * or outside (+1). Otherwise we're unsure (0). */\n"
- " int side;\n"
- " /* Offset to the arc-endpoints from the beginning of the glyph blob */\n"
- " int offset;\n"
- "\n"
- " /* A single line is all we care about. It's right here. */\n"
- " float line_angle;\n"
- " float line_distance; /* From nominal glyph center */\n"
- "};\n"
- "\n"
- "bool\n"
- "glyphy_isinf (const float v)\n"
- "{\n"
- " return abs (v) >= GLYPHY_INFINITY * .5;\n"
- "}\n"
- "\n"
- "bool\n"
- "glyphy_iszero (const float v)\n"
- "{\n"
- " return abs (v) <= GLYPHY_EPSILON * 2.;\n"
- "}\n"
- "\n"
- "vec2\n"
- "glyphy_ortho (const vec2 v)\n"
- "{\n"
- " return vec2 (-v.y, v.x);\n"
- "}\n"
- "\n"
- "int\n"
- "glyphy_float_to_byte (const float v)\n"
- "{\n"
- " return int (v * (256. - GLYPHY_EPSILON));\n"
- "}\n"
- "\n"
- "ivec4\n"
- "glyphy_vec4_to_bytes (const vec4 v)\n"
- "{\n"
- " return ivec4 (v * (256. - GLYPHY_EPSILON));\n"
- "}\n"
- "\n"
- "ivec2\n"
- "glyphy_float_to_two_nimbles (const float v)\n"
- "{\n"
- " int f = glyphy_float_to_byte (v);\n"
- " return ivec2 (f / 16, int(mod (float(f), 16.)));\n"
- "}\n"
- "\n"
- "/* returns tan (2 * atan (d)) */\n"
- "float\n"
- "glyphy_tan2atan (const float d)\n"
- "{\n"
- " return 2. * d / (1. - d * d);\n"
- "}\n"
- "\n"
- "glyphy_arc_endpoint_t\n"
- "glyphy_arc_endpoint_decode (const vec4 v, const ivec2 nominal_size)\n"
- "{\n"
- " vec2 p = (vec2 (glyphy_float_to_two_nimbles (v.a)) + v.gb) / 16.;\n"
- " float d = v.r;\n"
- " if (d == 0.)\n"
- " d = GLYPHY_INFINITY;\n"
- " else\n"
- "#define GLYPHY_MAX_D .5\n"
- " d = float(glyphy_float_to_byte (d) - 128) * GLYPHY_MAX_D / 127.;\n"
- "#undef GLYPHY_MAX_D\n"
- " return glyphy_arc_endpoint_t (p * vec2(nominal_size), d);\n"
- "}\n"
- "\n"
- "vec2\n"
- "glyphy_arc_center (const glyphy_arc_t a)\n"
- "{\n"
- " return mix (a.p0, a.p1, .5) +\n"
- " glyphy_ortho (a.p1 - a.p0) / (2. * glyphy_tan2atan (a.d));\n"
- "}\n"
- "\n"
- "bool\n"
- "glyphy_arc_wedge_contains (const glyphy_arc_t a, const vec2 p)\n"
- "{\n"
- " float d2 = glyphy_tan2atan (a.d);\n"
- " return dot (p - a.p0, (a.p1 - a.p0) * mat2(1, d2, -d2, 1)) >= 0. &&\n"
- " dot (p - a.p1, (a.p1 - a.p0) * mat2(1, -d2, d2, 1)) <= 0.;\n"
- "}\n"
- "\n"
- "float\n"
- "glyphy_arc_wedge_signed_dist_shallow (const glyphy_arc_t a, const vec2 p)\n"
- "{\n"
- " vec2 v = normalize (a.p1 - a.p0);\n"
- " float line_d = dot (p - a.p0, glyphy_ortho (v));\n"
- " if (a.d == 0.)\n"
- " return line_d;\n"
- "\n"
- " float d0 = dot ((p - a.p0), v);\n"
- " if (d0 < 0.)\n"
- " return sign (line_d) * distance (p, a.p0);\n"
- " float d1 = dot ((a.p1 - p), v);\n"
- " if (d1 < 0.)\n"
- " return sign (line_d) * distance (p, a.p1);\n"
- " float r = 2. * a.d * (d0 * d1) / (d0 + d1);\n"
- " if (r * line_d > 0.)\n"
- " return sign (line_d) * min (abs (line_d + r), min (distance (p, a.p0), distance (p, a.p1)));\n"
- " return line_d + r;\n"
- "}\n"
- "\n"
- "float\n"
- "glyphy_arc_wedge_signed_dist (const glyphy_arc_t a, const vec2 p)\n"
- "{\n"
- " if (abs (a.d) <= .03)\n"
- " return glyphy_arc_wedge_signed_dist_shallow (a, p);\n"
- " vec2 c = glyphy_arc_center (a);\n"
- " return sign (a.d) * (distance (a.p0, c) - distance (p, c));\n"
- "}\n"
- "\n"
- "float\n"
- "glyphy_arc_extended_dist (const glyphy_arc_t a, const vec2 p)\n"
- "{\n"
- " /* Note: this doesn't handle points inside the wedge. */\n"
- " vec2 m = mix (a.p0, a.p1, .5);\n"
- " float d2 = glyphy_tan2atan (a.d);\n"
- " if (dot (p - m, a.p1 - m) < 0.)\n"
- " return dot (p - a.p0, normalize ((a.p1 - a.p0) * mat2(+d2, -1, +1, +d2)));\n"
- " else\n"
- " return dot (p - a.p1, normalize ((a.p1 - a.p0) * mat2(-d2, -1, +1, -d2)));\n"
- "}\n"
- "\n"
- "int\n"
- "glyphy_arc_list_offset (const vec2 p, const ivec2 nominal_size)\n"
- "{\n"
- " ivec2 cell = ivec2 (clamp (floor (p), vec2 (0.,0.), vec2(nominal_size - 1)));\n"
- " return cell.y * nominal_size.x + cell.x;\n"
- "}\n"
- "\n"
- "glyphy_arc_list_t\n"
- "glyphy_arc_list_decode (const vec4 v, const ivec2 nominal_size)\n"
- "{\n"
- " glyphy_arc_list_t l;\n"
- " ivec4 iv = glyphy_vec4_to_bytes (v);\n"
- " l.side = 0; /* unsure */\n"
- " if (iv.r == 0) { /* arc-list encoded */\n"
- " l.offset = (iv.g * 256) + iv.b;\n"
- " l.num_endpoints = iv.a;\n"
- " if (l.num_endpoints == 255) {\n"
- " l.num_endpoints = 0;\n"
- " l.side = -1;\n"
- " } else if (l.num_endpoints == 0)\n"
- " l.side = +1;\n"
- " } else { /* single line encoded */\n"
- " l.num_endpoints = -1;\n"
- /*" l.line_distance = float(((iv.r - 128) * 256 + iv.g) - 0x4000) / float (0x1FFF)\n"
- " * max (float (nominal_size.x), float (nominal_size.y));\n"
- " l.line_angle = float(-((iv.b * 256 + iv.a) - 0x8000)) / float (0x7FFF) * 3.14159265358979;\n"*/
- /*" l.line_distance = float(((iv.r - 128) * 256 + iv.g) - 16384) / 8191.0 \n"
- " * max (float (nominal_size.x), float (nominal_size.y));\n"
- " l.line_angle = float(-((iv.b * 256 + iv.a) - 32768)) / 32767. * 3.14159;\n"*/
- " l.line_distance = ( float(iv.r)/32. + 0.01*float(iv.g)/82.0 - 6.) \n"
- " * max (float (nominal_size.x), float (nominal_size.y));\n"
- " l.line_angle = ( -float(iv.b)/40.74 - float( iv.a )*0.0001 )-3.142;\n"
- " }\n"
- " return l;\n"
- "}\n";
+++ /dev/null
-static const char* glyphy_sdf_glsl =
- "/*\n"
- " * Copyright 2012 Google, Inc. All Rights Reserved.\n"
- " *\n"
- " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
- " * you may not use this file except in compliance with the License.\n"
- " * You may obtain a copy of the License at\n"
- " *\n"
- " * http://www.apache.org/licenses/LICENSE-2.0\n"
- " *\n"
- " * Unless required by applicable law or agreed to in writing, software\n"
- " * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
- " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
- " * See the License for the specific language governing permissions and\n"
- " * limitations under the License.\n"
- " *\n"
- " * Google Author(s): Behdad Esfahbod, Maysum Panju\n"
- " */\n"
- "\n"
- "#ifndef GLYPHY_TEXTURE1D_FUNC\n"
- "#define GLYPHY_TEXTURE1D_FUNC glyphy_texture1D_func\n"
- "#endif\n"
- "#ifndef GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
- "#define GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
- "#endif\n"
- "#ifndef GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
- "#define GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
- "#endif\n"
- "\n"
- "#ifndef GLYPHY_SDF_TEXTURE1D_FUNC\n"
- "#define GLYPHY_SDF_TEXTURE1D_FUNC GLYPHY_TEXTURE1D_FUNC\n"
- "#endif\n"
- "#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS\n"
- "#define GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
- "#endif\n"
- "#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS\n"
- "#define GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
- "#endif\n"
- "#ifndef GLYPHY_SDF_TEXTURE1D\n"
- "#define GLYPHY_SDF_TEXTURE1D(offset) GLYPHY_RGBA(GLYPHY_SDF_TEXTURE1D_FUNC (offset GLYPHY_TEXTURE1D_EXTRA_ARGS))\n"
- "#endif\n"
- "\n"
- "#ifndef GLYPHY_MAX_NUM_ENDPOINTS\n"
- "#define GLYPHY_MAX_NUM_ENDPOINTS 32\n"
- "#endif\n"
- "\n"
- "glyphy_arc_list_t\n"
- "glyphy_arc_list (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
- "{\n"
- " int cell_offset = glyphy_arc_list_offset (p, nominal_size);\n"
- " vec4 arc_list_data = GLYPHY_SDF_TEXTURE1D (cell_offset);\n"
- " return glyphy_arc_list_decode (arc_list_data, nominal_size);\n"
- "}\n"
- "\n"
- "float\n"
- "glyphy_sdf (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
- "{\n"
- " glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);\n"
- "\n"
- " /* Short-circuits */\n"
- " if (arc_list.num_endpoints == 0) {\n"
- " /* far-away cell */\n"
- " return GLYPHY_INFINITY * float(arc_list.side);\n"
- " } if (arc_list.num_endpoints == -1) {\n"
- " /* single-line */\n"
- " float angle = arc_list.line_angle;\n"
- " vec2 n = vec2 (cos (angle), sin (angle));\n"
- " return dot (p - (vec2(nominal_size) * .5), n) - arc_list.line_distance;\n"
- " }\n"
- "\n"
- " float side = float(arc_list.side);\n"
- " float min_dist = GLYPHY_INFINITY;\n"
- " glyphy_arc_t closest_arc;\n"
- "\n"
- " glyphy_arc_endpoint_t endpoint_prev, endpoint;\n"
- " endpoint_prev = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset), nominal_size);\n"
- " for (int i = 1; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)\n"
- " {\n"
- " if (i >= arc_list.num_endpoints) {\n"
- " break;\n"
- " }\n"
- " endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);\n"
- " glyphy_arc_t a = glyphy_arc_t (endpoint_prev.p, endpoint.p, endpoint.d);\n"
- " endpoint_prev = endpoint;\n"
- " if (glyphy_isinf (a.d)) continue;\n"
- "\n"
- " if (glyphy_arc_wedge_contains (a, p))\n"
- " {\n"
- " float sdist = glyphy_arc_wedge_signed_dist (a, p);\n"
- " float udist = abs (sdist) * (1. - GLYPHY_EPSILON);\n"
- " if (udist <= min_dist) {\n"
- " min_dist = udist;\n"
- " side = sign (sdist);"
- " }\n"
- " } else {\n"
- " float udist = min (distance (p, a.p0), distance (p, a.p1));\n"
- " if (udist < min_dist) {\n"
- " min_dist = udist;\n"
- " side = 0.; /* unsure */\n"
- " closest_arc = a;\n"
- " } else if (side == 0. && udist == min_dist) {\n"
- " /* If this new distance is the same as the current minimum,\n"
- " * compare extended distances. Take the sign from the arc\n"
- " * with larger extended distance. */\n"
- " float old_ext_dist = glyphy_arc_extended_dist (closest_arc, p);\n"
- " float new_ext_dist = glyphy_arc_extended_dist (a, p);\n"
- "\n"
- " float ext_dist = abs (new_ext_dist) <= abs (old_ext_dist) ?\n"
- " old_ext_dist : new_ext_dist;\n"
- "\n"
- "#ifdef GLYPHY_SDF_PSEUDO_DISTANCE\n"
- " /* For emboldening and stuff: */\n"
- " min_dist = abs (ext_dist);\n"
- "#endif\n"
- " side = sign (ext_dist);\n"
- " }\n"
- " }\n"
- " }\n"
- "\n"
- " if (side == 0.) {\n"
- " // Technically speaking this should not happen, but it does. So try to fix it.\n"
- " float ext_dist = glyphy_arc_extended_dist (closest_arc, p);\n"
- " side = sign (ext_dist);\n"
- " }\n"
- "\n"
- " return min_dist * side;\n"
- "}\n"
- "\n"
- "float\n"
- "glyphy_point_dist (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
- "{\n"
- " glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);\n"
- "\n"
- " float side = float(arc_list.side);\n"
- " float min_dist = GLYPHY_INFINITY;\n"
- "\n"
- " if (arc_list.num_endpoints == 0)\n"
- " return min_dist;\n"
- "\n"
- " glyphy_arc_endpoint_t endpoint;\n"
- " for (int i = 0; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)\n"
- " {\n"
- " if (i >= arc_list.num_endpoints) {\n"
- " break;\n"
- " }\n"
- " endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);\n"
- " if (glyphy_isinf (endpoint.d)) continue;\n"
- " min_dist = min (min_dist, distance (p, endpoint.p));\n"
- " }\n"
- " return min_dist;\n"
- "}\n";
#include <sstream>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h>
-#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
using namespace Dali;
-namespace
-{
-const char* const ENABLE_EXTENSION_PREFIX =
- "#extension GL_OES_standard_derivatives : enable\n"
- "precision highp float;\n"
- "precision highp int;\n";
-
-const char* const VERTEX_SHADER_MAIN =
- "uniform mediump mat4 uProjection;\n"
- "uniform mediump mat4 uModelView;\n"
- "uniform mediump mat4 uMvpMatrix;\n"
- "uniform bool uTextureMapped;\n"
- "uniform mediump vec4 uCustomTextureCoords;\n"
- "attribute highp vec2 aTexCoord;\n"
- "varying mediump vec2 vTexCoord;\n"
- "uniform mat3 uModelViewIT;\n"
- "attribute mediump vec3 aNormal;\n"
- "varying mediump vec3 vNormal;\n"
- "attribute mediump vec2 aPosition;\n"
- "varying mediump vec4 vVertex;\n"
- "attribute mediump vec4 aColor;\n"
- "varying mediump vec4 vColor;\n"
- "varying vec4 v_glyph;\n"
- "\n"
- "vec4\n"
- "glyph_vertex_transcode (vec2 v)\n"
- "{\n"
- " ivec2 g = ivec2 (v);\n"
- " ivec2 corner = ivec2 (mod (v, 2.));\n"
- " g /= 2;\n"
- " ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));\n"
- " return vec4 (corner * nominal_size, g * 4);\n"
- "}\n"
- "\n"
- "void\n"
- "main()\n"
- "{\n"
- " gl_Position = uMvpMatrix * vec4 (aPosition, 0.0, 1.0);\n"
- " v_glyph = glyph_vertex_transcode (aTexCoord);\n"
- " vColor = aColor;\n"
- "}\n";
-
-const char* const FRAGMENT_SHADER_PREFIX =
- "struct Material\n"
- "{\n"
- " mediump float mOpacity;\n"
- " mediump float mShininess;\n"
- " lowp vec4 mAmbient;\n"
- " lowp vec4 mDiffuse;\n"
- " lowp vec4 mSpecular;\n"
- " lowp vec4 mEmissive;\n"
- "};\n"
- "uniform sampler2D sTexture;\n"
- "uniform sampler2D sOpacityTexture;\n"
- "uniform sampler2D sNormalMapTexture;\n"
- "uniform sampler2D sEffect;\n"
- "varying mediump vec2 vTexCoord;\n"
- "uniform Material uMaterial;\n"
- "uniform lowp vec4 uColor;\n"
- "varying highp vec4 vVertex;\n"
- "varying highp vec3 vNormal;\n"
- "varying mediump vec4 vColor;\n"
- "uniform vec4 u_atlas_info;\n"
- "\n"
- "#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos\n"
- "#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos\n"
- "#define GLYPHY_DEMO_EXTRA_ARGS , sTexture, uu_atlas_info, gi.atlas_pos\n"
- "\n"
- "vec4\n"
- "glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)\n"
- "{\n"
- " ivec2 item_geom = _atlas_info.zw;\n"
- " vec2 pos = (vec2 (_atlas_pos.xy * item_geom +\n"
- " ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +\n"
- " + vec2 (.5, .5)) / vec2(_atlas_info.xy);\n"
- " return texture2D (_tex, pos);\n"
- "}\n";
-
-static const char* FRAGMENT_SHADER_MAIN =
- "uniform float u_contrast;\n"
- "uniform float u_gamma_adjust;\n"
- "uniform float u_outline_thickness;\n"
- "uniform float u_outline;\n"
- "uniform float u_boldness;\n"
- "\n"
- "varying vec4 v_glyph;\n"
- "\n"
- "\n"
- "#define SQRT2_2 0.70711 /* 1 / sqrt(2.) */\n"
- "#define SQRT2 1.41421\n"
- "\n"
- "struct glyph_info_t {\n"
- " ivec2 nominal_size;\n"
- " ivec2 atlas_pos;\n"
- "};\n"
- "\n"
- "glyph_info_t\n"
- "glyph_info_decode (vec4 v)\n"
- "{\n"
- " glyph_info_t gi;\n"
- " gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;\n"
- " gi.atlas_pos = ivec2 (v_glyph.zw) / 256;\n"
- " return gi;\n"
- "}\n"
- "\n"
- "\n"
- "float\n"
- "antialias (float d)\n"
- "{\n"
- " return smoothstep (-.75, +.75, d);\n"
- "}\n"
- "\n"
- "vec4\n"
- "source_over (const vec4 src, const vec4 dst)\n"
- "{\n"
- " // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover\n"
- " float alpha = src.a + (dst.a * (1. - src.a));\n"
- " return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);\n"
- "}\n"
- "\n"
- "void\n"
- "main()\n"
- "{\n"
- " vec2 p = v_glyph.xy;\n"
- " glyph_info_t gi = glyph_info_decode (v_glyph);\n"
- "\n"
- " /* isotropic antialiasing */\n"
- " vec2 dpdx = dFdx (p);\n"
- " vec2 dpdy = dFdy (p);\n"
- " float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;\n"
- "\n"
- " vec4 color = vec4( vColor.rgb * uColor.rgb, vColor.a * uColor.a );\n"
- "\n"
- " ivec4 uu_atlas_info = ivec4( u_atlas_info );"
- " float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n"
- " float sdist = gsdist / m * u_contrast;\n"
- "\n"
- " sdist -= u_boldness * 10.;\n"
- " if ( glyphy_iszero( u_outline ) )\n"
- " sdist = abs (sdist) - u_outline_thickness * .5;\n"
- " if (sdist > 1.)\n"
- " discard;\n"
- " float alpha = antialias (-sdist);\n"
- " if (u_gamma_adjust != 1.)\n"
- " alpha = pow (alpha, 1./u_gamma_adjust);\n"
- " color = vec4 (color.rgb,color.a * alpha);\n"
- "\n"
- " gl_FragColor = color;\n"
- "}\n";
-
-} // namespace
-
namespace Dali
{
namespace Toolkit
std::ostringstream vertexShaderStringStream;
std::ostringstream fragmentShaderStringStream;
- vertexShaderStringStream << ENABLE_EXTENSION_PREFIX << VERTEX_SHADER_MAIN;
+ vertexShaderStringStream << SHADER_GLYPHY_SHADER_EXTENTION_PREFIX_DEF.data() << SHADER_GLYPHY_SHADER_MAIN_VERT.data();
- fragmentShaderStringStream << ENABLE_EXTENSION_PREFIX
- << FRAGMENT_SHADER_PREFIX
- << glyphy_common_glsl
+ fragmentShaderStringStream << SHADER_GLYPHY_SHADER_EXTENTION_PREFIX_DEF.data()
+ << SHADER_GLYPHY_SHADER_FRAGMENT_PREFIX_FRAG.data()
+ << SHADER_GLYPHY_COMMON_GLSL_SHADER_DEF.data()
<< "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n"
- << glyphy_sdf_glsl
- << FRAGMENT_SHADER_MAIN;
+ << SHADER_GLYPHY_SDF_GLSL_SHADER_DEF.data()
+ << SHADER_GLYPHY_SHADER_MAIN_FRAG.data();
Shader shaderEffectCustom = Shader::New(vertexShaderStringStream.str(),
fragmentShaderStringStream.str(),
return mModel->IsBackgroundEnabled();
}
+bool ViewModel::IsMarkupProcessorEnabled() const
+{
+ return mModel->IsMarkupProcessorEnabled();
+}
+
+const GlyphInfo* ViewModel::GetHyphens() const
+{
+ return mModel->GetHyphens();
+}
+
+const Length* ViewModel::GetHyphenIndices() const
+{
+ return mModel->GetHyphenIndices();
+}
+
+Length ViewModel::GetHyphensCount() const
+{
+ return mModel->GetHyphensCount();
+}
+
void ViewModel::ElideGlyphs()
{
mIsTextElided = false;
bool IsBackgroundEnabled() const override;
/**
+ * @copydoc ModelInterface::IsMarkupProcessorEnabled()
+ */
+ bool IsMarkupProcessorEnabled() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const GlyphInfo* GetHyphens() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const Length* GetHyphenIndices() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ Length GetHyphensCount() const override;
+
+ /**
* @brief Does the text elide.
*
* It stores a copy of the visible glyphs and removes as many glyphs as needed
eventData->mUpdateCursorPosition = false;
eventData->mUpdateGrabHandlePosition = false;
}
- else
+
+ if(eventData->mUpdateHighlightBox ||
+ eventData->mUpdateLeftSelectionPosition ||
+ eventData->mUpdateRightSelectionPosition)
{
CursorInfo leftHandleInfo;
CursorInfo rightHandleInfo;
#include <dali-toolkit/internal/text/character-set-conversion.h>
#include <dali-toolkit/internal/text/color-segmentation.h>
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
#include <dali-toolkit/internal/text/multi-language-support.h>
#include <dali-toolkit/internal/text/segmentation.h>
#include <dali-toolkit/internal/text/shaper.h>
#include <dali-toolkit/internal/text/text-run-container.h>
#include <dali-toolkit/internal/text/text-selection-handle-controller.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+
using namespace Dali;
namespace
Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
Vector<Character> displayCharacters;
bool useHiddenText = false;
- if(mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
+ if(mHiddenInput && mEventData != nullptr && !mEventData->mIsShowingPlaceholderText)
{
mHiddenInput->Substitute(srcCharacters, displayCharacters);
useHiddenText = true;
requestedNumberOfCharacters,
lineBreakInfo);
+ if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+ {
+ CharacterIndex end = startIndex + requestedNumberOfCharacters;
+ LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+ for(CharacterIndex index = startIndex; index < end; index++)
+ {
+ CharacterIndex wordEnd = index;
+ while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+ {
+ wordEnd++;
+ }
+
+ if((wordEnd + 1) == end) // add last char
+ {
+ wordEnd++;
+ }
+
+ Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+ for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+ {
+ if(hyphens[i])
+ {
+ *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+ }
+ }
+
+ index = wordEnd;
+ }
+ }
+
// Create the paragraph info.
mModel->mLogicalModel->CreateParagraphInfo(startIndex,
requestedNumberOfCharacters);
TextAbstraction::FontDescription defaultFontDescription;
TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
- if(IsShowingPlaceholderText() && mEventData && (NULL != mEventData->mPlaceholderFont))
+ //Get the number of points per one unit of point-size
+ uint32_t numberOfPointsPerOneUnitOfPointSize = mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
+
+ if(IsShowingPlaceholderText() && mEventData && (nullptr != mEventData->mPlaceholderFont))
{
// If the placeholder font is set specifically, only placeholder font is changed.
defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
if(mEventData->mPlaceholderFont->sizeDefined)
{
- defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * 64u;
+ defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
}
}
- else if(NULL != mFontDefaults)
+ else if(nullptr != mFontDefaults)
{
// Set the normal font and the placeholder font.
defaultFontDescription = mFontDefaults->mFontDescription;
if(mTextFitEnabled)
{
- defaultPointSize = mFontDefaults->mFitPointSize * 64u;
+ defaultPointSize = mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
}
else
{
- defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * 64u;
+ defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
}
}
// Create the 'number of glyphs' per character and the glyph to character conversion tables.
mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
- updated = true;
+
+ updated = true;
}
const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
updated = true;
}
- if((NULL != mEventData) &&
+ if((nullptr != mEventData) &&
mEventData->mPreEditFlag &&
(0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
{
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::REVERSE:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::NONE:
updated = true;
}
+ if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
+ ! ((nullptr != mEventData) &&
+ mEventData->mPreEditFlag &&
+ (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
+ {
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(true);
+ }
+
+ updated = true;
+ }
+
+
// The estimated number of lines. Used to avoid reallocations when layouting.
mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
float Controller::Impl::GetDefaultFontLineHeight()
{
FontId defaultFontId = 0u;
- if(NULL == mFontDefaults)
+ if(nullptr == mFontDefaults)
{
TextAbstraction::FontDescription fontDescription;
defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
void Controller::Impl::ChangeState(EventData::State newState)
{
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
return;
CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
{
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
return 0u;
void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
void Controller::Impl::RequestRelayout()
{
- if(NULL != mControlInterface)
+ if(nullptr != mControlInterface)
{
mControlInterface->RequestTextRelayout();
}
return actor;
}
+void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
+{
+ //Underlined character runs for markup-processor
+ const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ if(shouldClearPreUnderlineRuns)
+ {
+ mModel->mVisualModel->mUnderlineRuns.Clear();
+ }
+
+ for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+ {
+ CharacterIndex characterIndex = it->characterRun.characterIndex;
+ Length numberOfCharacters = it->characterRun.numberOfCharacters;
+ for(Length index=0u; index<numberOfCharacters; index++)
+ {
+ GlyphRun underlineGlyphRun;
+ underlineGlyphRun.glyphIndex = charactersToGlyph[characterIndex + index];
+ underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+ mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
+ }
+ }
+}
+
} // namespace Text
} // namespace Toolkit
// Declared private and left undefined to avoid copies.
Impl& operator=(const Impl&);
+ /**
+ * @brief Copy Underlined-Character-Runs from Logical-Model to Underlined-Glyph-Runs in Visual-Model
+ *
+ * @param shouldClearPreUnderlineRuns Whether should clear the existing Underlined-Glyph-Runs in Visual-Model
+ */
+ void CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns);
+
public:
ControlInterface* mControlInterface; ///< Reference to the text controller.
EditableControlInterface* mEditableControlInterface; ///< Reference to the editable text controller.
// The implementation of Get LineCount property depends on calling GetHeightForWidth then read mLines.Count() from visualModel direct.
// If the LineCount property is requested before rendering and layouting then the value will be zero, which is incorrect.
// So we will not restore the previously backed-up mLines and mGlyphPositions from visualModel in such case.
- bool restoreLinesAndGlyphPositions = visualModel->mControlSize.width>0 && visualModel->mControlSize.height>0;
+ // Another case to skip restore is when the requested width equals the Control's width which means the caller need to update the old values.
+ // For example, when the text is changed.
+ bool restoreLinesAndGlyphPositions = (visualModel->mControlSize.width>0 && visualModel->mControlSize.height>0)
+ && (visualModel->mControlSize.width != width);
layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask, restoreLinesAndGlyphPositions);
MarkupProcessData markupProcessData(logicalModel->mColorRuns,
logicalModel->mFontDescriptionRuns,
logicalModel->mEmbeddedItems,
- logicalModel->mAnchors);
+ logicalModel->mAnchors,
+ logicalModel->mUnderlinedCharacterRuns);
Length textSize = 0u;
const uint8_t* utf8 = NULL;
#include <limits>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
#include <dali-toolkit/internal/text/text-controller-event-handler.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
#include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
GetText(text);
SetText(text);
}
+
+ mImpl->mModel->mVisualModel->SetMarkupProcessorEnabled(enable);
}
bool Controller::IsMarkupProcessorEnabled() const
{
if(lineWrapMode != mImpl->mModel->mLineWrapMode)
{
- // Set the text wrap mode.
- mImpl->mModel->mLineWrapMode = lineWrapMode;
-
// Update Text layout for applying wrap mode
- mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
+ mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
ALIGN |
LAYOUT |
UPDATE_LAYOUT_SIZE |
REORDER);
+
+ if((mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ (mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
+ {
+ mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | GET_LINE_BREAKS);
+ }
+
+ // Set the text wrap mode.
+ mImpl->mModel->mLineWrapMode = lineWrapMode;
+
mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
* @return The background state.
*/
virtual bool IsBackgroundEnabled() const = 0;
+
+ /**
+ * @brief Returns whether markup-processor is enabled or not.
+ *
+ * @return The markup-processor state.
+ */
+ virtual bool IsMarkupProcessorEnabled() const = 0;
+
+ /**
+ * @brief Returns the hyphens glyph info.
+ *
+ * @return hyphens glyph info.
+ */
+ virtual const GlyphInfo* GetHyphens() const = 0;
+
+ /**
+ * @brief Returns the indices of the hyphen in the text.
+ *
+ * @return the hyphen indices.
+ */
+ virtual const Length* GetHyphenIndices() const = 0;
+
+ /**
+ * @brief Returns number of hyphens to add in text.
+ *
+ * @return number of hyphens.
+ */
+ virtual Length GetHyphensCount() const = 0;
};
} // namespace Text
return mVisualModel->IsBackgroundEnabled();
}
+bool Model::IsMarkupProcessorEnabled() const
+{
+ return mVisualModel->IsMarkupProcessorEnabled();
+}
+
+const GlyphInfo* Model::GetHyphens() const
+{
+ return mVisualModel->mHyphen.glyph.Begin();
+}
+
+const Length* Model::GetHyphenIndices() const
+{
+ return mVisualModel->mHyphen.index.Begin();
+}
+
+Length Model::GetHyphensCount() const
+{
+ return mVisualModel->mHyphen.glyph.Size();
+}
+
Model::Model()
: mLogicalModel(),
mVisualModel(),
*/
bool IsBackgroundEnabled() const override;
+ /**
+ * @copydoc ModelInterface::IsMarkupProcessorEnabled()
+ */
+ bool IsMarkupProcessorEnabled() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const GlyphInfo* GetHyphens() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const Length* GetHyphenIndices() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ Length GetHyphensCount() const override;
+
private: // Private contructors & copy operator.
/**
* @brief Private constructor.
virtual bool IsUnderlineEnabled() const = 0;
/**
+ * @brief Returns the hyphens glyph info.
+ *
+ * @return hyphens glyph info.
+ */
+ virtual const GlyphInfo* GetHyphens() const = 0;
+
+ /**
+ * @brief Returns the indices of the hyphen in the text.
+ *
+ * @return the hyphen indices.
+ */
+ virtual const Length* GetHyphenIndices() const = 0;
+
+ /**
+ * @brief Returns number of hyphens to add in text.
+ *
+ * @return number of hyphens.
+ */
+ virtual Length GetHyphensCount() const = 0;
+ /**
* @brief Retrieves the underline height override
*
* @return Returns the override height for an underline, 0 indicates that adaptor will determine the height
return false;
}
+const GlyphInfo* View::GetHyphens() const
+{
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->mHyphen.glyph.Begin();
+ }
+
+ return nullptr;
+}
+
+const Length* View::GetHyphenIndices() const
+{
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->mHyphen.index.Begin();
+ }
+
+ return nullptr;
+}
+
+Length View::GetHyphensCount() const
+{
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->mHyphen.glyph.Size();
+ }
+
+ return 0;
+}
float View::GetUnderlineHeight() const
{
if(mImpl->mVisualModel)
bool IsUnderlineEnabled() const override;
/**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+ */
+ const GlyphInfo* GetHyphens() const override;
+
+ /**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+ */
+ const Length* GetHyphenIndices() const override;
+
+ /**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+ */
+ Length GetHyphensCount() const override;
+
+ /**
* @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineHeight()
*/
float GetUnderlineHeight() const override;
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_UNDERLINED_CHARACTER_RUN_H
+#define DALI_TOOLKIT_TEXT_UNDERLINED_CHARACTER_RUN_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/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/internal/text/glyph-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Run of underlined characters with same properties.
+ */
+struct UnderlinedCharacterRun
+{
+ CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
+ //TODO: add properties like color, height and style
+ //Vector4 color; ///< The color of underline.
+ //float height; ///< The height of underline.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UNDERLINED_CHARACTER_RUN_H
mBackgroundEnabled = enabled;
}
+void VisualModel::SetMarkupProcessorEnabled(bool enabled)
+{
+ mMarkupProcessorEnabled = enabled;
+}
+
const Vector4& VisualModel::GetTextColor() const
{
return mTextColor;
return mBackgroundEnabled;
}
+bool VisualModel::IsMarkupProcessorEnabled() const
+{
+ return mMarkupProcessorEnabled;
+}
+
Length VisualModel::GetNumberOfUnderlineRuns() const
{
return mUnderlineRuns.Count();
mCachedLineIndex(0u),
mUnderlineEnabled(false),
mUnderlineColorSet(false),
- mBackgroundEnabled(false)
+ mBackgroundEnabled(false),
+ mMarkupProcessorEnabled(false)
{
}
{
namespace Text
{
+struct HyphenInfo
+{
+ Vector<GlyphInfo> glyph;
+ Vector<Vector2> position;
+ Vector<Length> index;
+};
+
class VisualModel;
typedef IntrusivePtr<VisualModel> VisualModelPtr;
*/
bool IsBackgroundEnabled() const;
+ /**
+ * @brief Sets whether the text has a markup-processor or not.
+ *
+ * @param[in] enabled true if the text has a markup-processor.
+ */
+ void SetMarkupProcessorEnabled(bool enabled);
+
+ /**
+ * @brief Returns whether the text has a markup-processor or not.
+ *
+ * @return whether the text has a markup-processor or not.
+ */
+ bool IsMarkupProcessorEnabled() const;
+
protected:
/**
* @brief A reference counted object may only be deleted by calling Unreference().
bool mUnderlineEnabled : 1; ///< Underline enabled flag
bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set?
bool mBackgroundEnabled : 1; ///< Background enabled flag
+ bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
+ HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after.
};
} // namespace Text
{
bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
bool atlasing = false;
- Shader shader = mImageVisualShaderFactory.GetShader(mFactoryCache, atlasing, defaultWrapMode, IsRoundedCornerRequired());
+ Shader shader = mImageVisualShaderFactory.GetShader(
+ mFactoryCache,
+ atlasing ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+ defaultWrapMode ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
+ IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+ IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+ );
Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
}
else
{
- shader = mImageVisualShaderFactory.GetShader(mFactoryCache, false, true, IsRoundedCornerRequired());
+ shader = mImageVisualShaderFactory.GetShader(
+ mFactoryCache,
+ TextureAtlas::DISABLED,
+ DefaultTextureWrapMode::APPLY,
+ IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+ IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+ );
}
Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
namespace
{
constexpr auto LOOP_FOREVER = -1;
-constexpr auto NANOSECONDS_PER_SECOND(1e+9);
+constexpr auto MICROSECONDS_PER_SECOND(1e+6);
#if defined(DEBUG_ENABLED)
Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
mLoopingMode(DevelImageVisual::LoopingMode::RESTART),
mNextFrameStartTime(),
- mFrameDurationNanoSeconds(0),
+ mFrameDurationMicroSeconds(MICROSECONDS_PER_SECOND / 60.0f),
mFrameRate(60.0f),
mCurrentFrame(0),
mTotalFrame(0),
mStartFrame(0),
mEndFrame(0),
+ mDroppedFrames(0),
mWidth(0),
mHeight(0),
mAnimationDataIndex(0),
mEndFrame = mTotalFrame - 1;
- mFrameRate = mVectorRenderer.GetFrameRate();
- mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
+ mFrameRate = mVectorRenderer.GetFrameRate();
+ mFrameDurationMicroSeconds = MICROSECONDS_PER_SECOND / mFrameRate;
uint32_t width, height;
mVectorRenderer.GetDefaultSize(width, height);
if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber)
{
- mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
+ mCurrentFrame = mForward ? mCurrentFrame + mDroppedFrames + 1 : mCurrentFrame - mDroppedFrames - 1;
Dali::ClampInPlace(mCurrentFrame, mStartFrame, mEndFrame);
}
return frame;
}
-std::chrono::time_point<std::chrono::system_clock> VectorAnimationTask::CalculateNextFrameTime(bool renderNow)
+VectorAnimationTask::TimePoint VectorAnimationTask::CalculateNextFrameTime(bool renderNow)
{
// std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
// duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
// is casted to use the default duration.
- mNextFrameStartTime = std::chrono::time_point_cast<std::chrono::time_point<std::chrono::system_clock>::duration>(
- mNextFrameStartTime + std::chrono::nanoseconds(mFrameDurationNanoSeconds));
- auto current = std::chrono::system_clock::now();
- if(renderNow || mNextFrameStartTime < current)
+ mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
+ auto current = std::chrono::system_clock::now();
+ if(renderNow)
{
mNextFrameStartTime = current;
+ mDroppedFrames = 0;
}
+ else if(mNextFrameStartTime < current)
+ {
+ uint32_t droppedFrames = 0;
+
+ while(current > std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)))
+ {
+ droppedFrames++;
+ mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
+ }
+
+ mNextFrameStartTime = current;
+ mDroppedFrames = droppedFrames;
+ }
+
return mNextFrameStartTime;
}
-std::chrono::time_point<std::chrono::system_clock> VectorAnimationTask::GetNextFrameTime()
+VectorAnimationTask::TimePoint VectorAnimationTask::GetNextFrameTime()
{
return mNextFrameStartTime;
}
public:
using UploadCompletedSignalType = Dali::VectorAnimationRenderer::UploadCompletedSignalType;
+ using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
+
/**
* Flags for re-sending data to the vector animation thread
*/
* @brief Calculates the time for the next frame rasterization.
* @return The time for the next frame rasterization.
*/
- std::chrono::time_point<std::chrono::system_clock> CalculateNextFrameTime(bool renderNow);
+ TimePoint CalculateNextFrameTime(bool renderNow);
/**
* @brief Gets the time for the next frame rasterization.
* @return The time for the next frame rasterization.
*/
- std::chrono::time_point<std::chrono::system_clock> GetNextFrameTime();
+ TimePoint GetNextFrameTime();
private:
/**
PAUSED ///< The animation is paused
};
- std::string mUrl;
- VectorAnimationRenderer mVectorRenderer;
- AnimationData mAnimationData[2];
- VectorAnimationThread& mVectorAnimationThread;
- ConditionalWait mConditionalWait;
- std::unique_ptr<EventThreadCallback> mAnimationFinishedTrigger;
- PlayState mPlayState;
- DevelImageVisual::StopBehavior::Type mStopBehavior;
- DevelImageVisual::LoopingMode::Type mLoopingMode;
- std::chrono::time_point<std::chrono::system_clock> mNextFrameStartTime;
- int64_t mFrameDurationNanoSeconds;
- float mFrameRate;
- uint32_t mCurrentFrame;
- uint32_t mTotalFrame;
- uint32_t mStartFrame;
- uint32_t mEndFrame;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mAnimationDataIndex;
- int32_t mLoopCount;
- int32_t mCurrentLoop;
- bool mForward;
- bool mUpdateFrameNumber;
- bool mNeedAnimationFinishedTrigger;
- bool mAnimationDataUpdated;
- bool mDestroyTask;
+ std::string mUrl;
+ VectorAnimationRenderer mVectorRenderer;
+ AnimationData mAnimationData[2];
+ VectorAnimationThread& mVectorAnimationThread;
+ ConditionalWait mConditionalWait;
+ std::unique_ptr<EventThreadCallback> mAnimationFinishedTrigger;
+ PlayState mPlayState;
+ DevelImageVisual::StopBehavior::Type mStopBehavior;
+ DevelImageVisual::LoopingMode::Type mLoopingMode;
+ TimePoint mNextFrameStartTime;
+ int64_t mFrameDurationMicroSeconds;
+ float mFrameRate;
+ uint32_t mCurrentFrame;
+ uint32_t mTotalFrame;
+ uint32_t mStartFrame;
+ uint32_t mEndFrame;
+ uint32_t mDroppedFrames;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mAnimationDataIndex;
+ int32_t mLoopCount;
+ int32_t mCurrentLoop;
+ bool mForward;
+ bool mUpdateFrameNumber;
+ bool mNeedAnimationFinishedTrigger;
+ bool mAnimationDataUpdated;
+ bool mDestroyTask;
};
} // namespace Internal
{
namespace Internal
{
+namespace
+{
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[6] =
+{
+ VisualFactoryCache::COLOR_SHADER,
+ VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER,
+ VisualFactoryCache::COLOR_SHADER_BORDERLINE,
+ VisualFactoryCache::COLOR_SHADER_ROUNDED_BORDERLINE,
+ VisualFactoryCache::COLOR_SHADER_BLUR_EDGE,
+ VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE,
+};
+
+// enum of required list when we select shader
+enum ColorVisualRequireFlag
+{
+ DEFAULT = 0,
+ ROUNDED_CORNER = 1 << 0,
+ BORDERLINE = 1 << 1,
+ BLUR = 1 << 2,
+};
+} // unnamed namespace
ColorVisualPtr ColorVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
{
ColorVisualPtr colorVisualPtr(new ColorVisual(factoryCache));
: Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::COLOR),
mBlurRadius(0.0f),
mBlurRadiusIndex(Property::INVALID_INDEX),
- mRenderIfTransparent(false),
mNeedBlurRadius(false)
{
}
}
}
- Property::Value* renderIfTransparentValue = propertyMap.Find(Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, RENDER_IF_TRANSPARENT_NAME);
- if(renderIfTransparentValue)
- {
- if(!renderIfTransparentValue->Get(mRenderIfTransparent))
- {
- DALI_LOG_ERROR("ColorVisual: renderIfTransparent property has incorrect type: %d\n", renderIfTransparentValue->GetType());
- }
- }
-
Property::Value* blurRadiusValue = propertyMap.Find(Toolkit::DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME);
if(blurRadiusValue)
{
void ColorVisual::DoSetOnScene(Actor& actor)
{
- // Only add the renderer if it's not fully transparent
- // We cannot avoid creating a renderer as it's used in the base class
- if(mRenderIfTransparent || mImpl->mMixColor.a > 0.0f)
- {
- actor.AddRenderer(mImpl->mRenderer);
- }
+ actor.AddRenderer(mImpl->mRenderer);
// Color Visual generated and ready to display
ResourceReady(Toolkit::Visual::ResourceStatus::READY);
map.Clear();
map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
map.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor);
- map.Insert(Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, mRenderIfTransparent);
if(mImpl->mRenderer && mBlurRadiusIndex != Property::INVALID_INDEX)
{
Shader ColorVisual::GetShader()
{
Shader shader;
- if(!EqualsZero(mBlurRadius) || mNeedBlurRadius)
+ VisualFactoryCache::ShaderType shaderType;
+
+ bool roundedCorner = IsRoundedCornerRequired();
+ bool borderline = IsBorderlineRequired();
+ bool blur = !EqualsZero(mBlurRadius) || mNeedBlurRadius;
+ int shaderTypeFlag = ColorVisualRequireFlag::DEFAULT;
+
+ if(roundedCorner)
{
- shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER_BLUR_EDGE);
- if(!shader)
- {
- shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_BLUR_EDGE_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_BLUR_EDGE_SHADER_FRAG.data());
- mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER_BLUR_EDGE, shader);
- }
+ shaderTypeFlag |= ColorVisualRequireFlag::ROUNDED_CORNER;
}
- else if(!IsRoundedCornerRequired())
+ if(blur)
{
- shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER);
- if(!shader)
- {
- shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_SHADER_FRAG.data());
- mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER, shader);
- }
+ // If we use blur, just ignore borderline
+ borderline = false;
+ shaderTypeFlag |= ColorVisualRequireFlag::BLUR;
}
- else
+ if(borderline)
+ {
+ shaderTypeFlag |= ColorVisualRequireFlag::BORDERLINE;
+ }
+
+ shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+ shader = mFactoryCache.GetShader(shaderType);
+ if(!shader)
{
- shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER);
- if(!shader)
+ std::string vertexShaderPrefixList;
+ std::string fragmentShaderPrefixList;
+ if(roundedCorner)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+ }
+ if(blur)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_BLUR 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_BLUR 1\n";
+ }
+ if(borderline)
{
- shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_ROUNDED_CORNER_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_ROUNDED_CORNER_SHADER_FRAG.data());
- mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER, shader);
+ vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
}
+ shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_COLOR_VISUAL_SHADER_VERT.data(),
+ Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_COLOR_VISUAL_SHADER_FRAG.data());
+ mFactoryCache.SaveShader(shaderType, shader);
}
return shader;
ColorVisual& operator=(const ColorVisual& colorRenderer);
private:
- float mBlurRadius; ///< The blur radius
- Property::Index mBlurRadiusIndex; ///< The blur radius property index
- bool mRenderIfTransparent; ///< Whether we should render even if the mix-color is transparent.
- bool mNeedBlurRadius; ///< Whether we need the blur radius in shader.
+ float mBlurRadius; ///< The blur radius
+ Property::Index mBlurRadiusIndex; ///< The blur radius property index
+ bool mNeedBlurRadius; ///< Whether we need the blur radius in shader.
};
} // namespace Internal
#include <typeinfo>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-rounded-corner-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-rounded-corner-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-rounded-corner-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-rounded-corner-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-shader-vert.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
#include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
#include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
-VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[][4] =
- {
- {VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
- VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
- VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
- VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER},
- {VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
- VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
- VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
- VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER}};
-
-const std::string_view VERTEX_SHADER[] =
- {
- // vertex shader for gradient units as OBJECT_BOUNDING_BOX
- SHADER_GRADIENT_VISUAL_BOUNDING_BOX_SHADER_VERT,
-
- // vertex shader for gradient units as USER_SPACE
- SHADER_GRADIENT_VISUAL_USER_SPACE_SHADER_VERT,
-
- // vertex shader for gradient units as OBJECT_BOUNDING_BOX with corner radius
- SHADER_GRADIENT_VISUAL_BOUNDING_BOX_ROUNDED_CORNER_SHADER_VERT,
-
- // vertex shader for gradient units as USER_SPACE with corner radius
- SHADER_GRADIENT_VISUAL_USER_SPACE_ROUNDED_CORNER_SHADER_VERT};
-
-const std::string_view FRAGMENT_SHADER[] =
- {
- // fragment shader for linear gradient
- SHADER_GRADIENT_VISUAL_LINEAR_SHADER_FRAG,
-
- // fragment shader for radial gradient
- SHADER_GRADIENT_VISUAL_RADIAL_SHADER_FRAG,
-
- // fragment shader for linear gradient with corner radius
- SHADER_GRADIENT_VISUAL_LINEAR_ROUNDED_CORNER_SHADER_FRAG,
-
- // fragment shader for radial gradient with corner radius
- SHADER_GRADIENT_VISUAL_RADIAL_ROUNDED_CORNER_SHADER_FRAG};
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[16] =
+{
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER,
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_BORDERLINE,
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_BORDERLINE,
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_BORDERLINE,
+ VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_BORDERLINE,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_BORDERLINE,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_BORDERLINE,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
+ VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
+};
+
+// enum of required list when we select shader
+enum GradientVisualRequireFlag
+{
+ DEFAULT = 0,
+ ROUNDED_CORNER = 1 << 0,
+ BORDERLINE = 1 << 1,
+ USER_SPACE = 1 << 2,
+ RADIAL = 1 << 3,
+};
Dali::WrapMode::Type GetWrapMode(Toolkit::GradientVisual::SpreadMethod::Type spread)
{
Scripting::GetEnumerationProperty(*unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits);
}
- mGradientType = LINEAR;
+ mGradientType = Type::LINEAR;
if(propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME))
{
- mGradientType = RADIAL;
+ mGradientType = Type::RADIAL;
}
if(NewGradient(mGradientType, propertyMap))
bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
{
- if(gradientType == LINEAR)
+ if(gradientType == Type::LINEAR)
{
Property::Value* startPositionValue = propertyMap.Find(Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME);
Property::Value* endPositionValue = propertyMap.Find(Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME);
return false;
}
}
- else // type==RADIAL
+ else // type==Type::RADIAL
{
Property::Value* centerValue = propertyMap.Find(Toolkit::GradientVisual::Property::CENTER, CENTER_NAME);
Property::Value* radiusValue = propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME);
Shader GradientVisual::GetShader()
{
- Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
- int roundedCorner = IsRoundedCornerRequired() ? 1 : 0;
- VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[mGradientType][gradientUnits + roundedCorner * 2];
- Shader shader = mFactoryCache.GetShader(shaderType);
+ bool userspaceUnit = (mGradient->GetGradientUnits() == Toolkit::GradientVisual::Units::USER_SPACE);
+ bool roundedCorner = IsRoundedCornerRequired();
+ bool borderline = IsBorderlineRequired();
+ bool radialGradient = (mGradientType == Type::RADIAL);
+
+ int shaderTypeFlag = GradientVisualRequireFlag::DEFAULT;
+ if(roundedCorner)
+ {
+ shaderTypeFlag |= GradientVisualRequireFlag::ROUNDED_CORNER;
+ }
+ if(borderline)
+ {
+ shaderTypeFlag |= GradientVisualRequireFlag::BORDERLINE;
+ }
+ if(userspaceUnit)
+ {
+ shaderTypeFlag |= GradientVisualRequireFlag::USER_SPACE;
+ }
+ if(radialGradient)
+ {
+ shaderTypeFlag |= GradientVisualRequireFlag::RADIAL;
+ }
+
+ VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+ Shader shader = mFactoryCache.GetShader(shaderType);
if(!shader)
{
- shader = Shader::New(VERTEX_SHADER[gradientUnits + roundedCorner * 2], FRAGMENT_SHADER[mGradientType + roundedCorner * 2]);
+ std::string vertexShaderPrefixList;
+ std::string fragmentShaderPrefixList;
+
+ if(roundedCorner)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+ }
+ if(borderline)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+ }
+ if(radialGradient)
+ {
+ fragmentShaderPrefixList += "#define RADIAL 1\n";
+ }
+ if(userspaceUnit)
+ {
+ vertexShaderPrefixList += "#define USER_SPACE 1\n";
+ }
+
+ shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_GRADIENT_VISUAL_SHADER_VERT.data(),
+ Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_GRADIENT_VISUAL_SHADER_FRAG.data());
mFactoryCache.SaveShader(shaderType, shader);
}
{
}
-Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner)
+Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline)
{
Shader shader;
- if(atlasing)
+ VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER;
+ if(atlasing == TextureAtlas::ENABLED)
{
- if(defaultTextureWrapping)
+ if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
{
- shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP);
- if(!shader)
+ shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP;
+ }
+ else
+ {
+ shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP;
+ }
+ }
+ else
+ {
+ if(roundedCorner == RoundedCorner::ENABLED)
+ {
+ if(borderline == Borderline::ENABLED)
{
- shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
- Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ATLAS_CLAMP_SHADER_FRAG.data());
- shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
- factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader);
+ shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE;
+ }
+ else
+ {
+ shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER;
}
}
else
{
- shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP);
- if(!shader)
+ if(borderline == Borderline::ENABLED)
{
- shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
- Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ATLAS_VARIOUS_WRAP_SHADER_FRAG.data());
- shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
- factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP, shader);
+ shaderType = VisualFactoryCache::IMAGE_SHADER_BORDERLINE;
}
}
}
- else
+
+ shader = factoryCache.GetShader(shaderType);
+ if(!shader)
{
- if(roundedCorner)
+ std::string vertexShaderPrefixList;
+ std::string fragmentShaderPrefixList;
+ if(atlasing == TextureAtlas::ENABLED)
{
- shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER);
- if(!shader)
+ if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
+ {
+ fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP 1\n";
+ }
+ else
{
- shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_ROUNDED_CORNER_SHADER_VERT.data(),
- Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ROUNDED_CORNER_SHADER_FRAG.data());
- shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
- factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, shader);
+ fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP 1\n";
}
}
else
{
- shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER);
- if(!shader)
+ if(roundedCorner == RoundedCorner::ENABLED)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+ }
+ if(borderline == Borderline::ENABLED)
{
- shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
- Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_NO_ATLAS_SHADER_FRAG.data());
- shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
- factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER, shader);
+ vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
}
}
+
+ shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
+ Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_FRAG.data());
+ shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+ factoryCache.SaveShader(shaderType, shader);
}
return shader;
{
if(gFragmentShaderNoAtlas.empty())
{
- gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_NO_ATLAS_SHADER_FRAG.data();
+ gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_FRAG.data();
}
return gFragmentShaderNoAtlas;
}
namespace Internal
{
/**
+ * @brief Whether use texture with atlas, or not
+ */
+enum class TextureAtlas
+{
+ DISABLED = 0, ///< Image visual use ATLAS
+ ENABLED ///< Image visual doesn't use ATLAS
+};
+
+/**
+ * @brief Whether apply to texture wraping in default, or not
+ */
+enum class DefaultTextureWrapMode
+{
+ DO_NOT_APPLY = 0, ///< Image visual doesn't apply to wraping texture in default
+ APPLY ///< Image visual apply to wraping texture in default
+};
+
+/**
+ * @brief Whether use rounded corner, or not
+ */
+enum class RoundedCorner
+{
+ DISABLED = 0, ///< Image visual doesn't use rounded corner
+ ENABLED ///< Image visual use rounded corner
+};
+
+/**
+ * @brief Whether use borderline, or not
+ */
+enum class Borderline
+{
+ DISABLED = 0, ///< Image visual doesn't use borderline
+ ENABLED ///< Image visual use borderline
+};
+
+/**
* ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
*/
class ImageVisualShaderFactory
{
public:
+
/**
* @brief Constructor
*/
* @param[in] atlasing Whether texture atlasing is applied.
* @param[in] defaultTextureWrapping Whether the default texture wrap mode is applied.
* @param[in] roundedCorner Whether the rounded corder is applied.
+ * @param[in] borderline Whether the borderline of visual is applied.
*/
- Shader GetShader(VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner);
+ Shader GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline);
/**
* Request the default vertex shader source.
if(mTextures)
{
mImpl->mRenderer.SetTextures(mTextures);
+ if(DevelTexture::IsNative(mTextures.GetTexture(0)))
+ {
+ UpdateShader();
+ }
mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
}
// Create and cache the standard shader
shader = mImageVisualShaderFactory.GetShader(
mFactoryCache,
- mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
- mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE,
- IsRoundedCornerRequired());
+ mImpl->mFlags & Impl::IS_ATLASING_APPLIED ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+ mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
+ IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+ IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+ );
}
else if(mImpl->mCustomShader)
{
{
// Get basic geometry and shader
Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
- Shader shader = mImageVisualShaderFactory.GetShader(mFactoryCache, false, true, false);
+ Shader shader = mImageVisualShaderFactory.GetShader(
+ mFactoryCache,
+ TextureAtlas::DISABLED,
+ DefaultTextureWrapMode::APPLY,
+ RoundedCorner::DISABLED,
+ Borderline::DISABLED
+ );
mImpl->mRenderer = Renderer::New(geometry, shader);
Shader shader;
if(!mImpl->mCustomShader)
{
- shader = mImageVisualShaderFactory.GetShader(mFactoryCache, mAttemptAtlasing, true, IsRoundedCornerRequired());
+ shader = mImageVisualShaderFactory.GetShader(
+ mFactoryCache,
+ mAttemptAtlasing ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+ DefaultTextureWrapMode::APPLY,
+ IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+ IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+ );
}
else
{
shadowEnabled = true;
}
- const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
- const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
- const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();
- ;
+ const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
+ const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
+ const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();
+ const bool markupProcessorEnabled = mController->IsMarkupProcessorEnabled();
- const bool styleEnabled = (shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled);
+ const bool styleEnabled = (shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled);
AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled);
{
if(element.mObserver == observer)
{
- mLoadQueue.Erase(&element);
+ // Do not erase the item. We will clear it later in ProcessQueuedTextures().
+ element.mObserver = nullptr;
break;
}
}
mTransform(),
mMixColor(Color::WHITE),
mControlSize(Vector2::ZERO),
+ mBorderlineWidth(0.0f),
+ mBorderlineColor(Color::BLACK),
+ mBorderlineOffset(0.0f),
mCornerRadius(Vector4::ZERO),
mCornerRadiusPolicy(1.0f),
mDepthIndex(0.0f),
mMixColorIndex(Property::INVALID_INDEX),
+ mBorderlineWidthIndex(Property::INVALID_INDEX),
+ mBorderlineColorIndex(Property::INVALID_INDEX),
+ mBorderlineOffsetIndex(Property::INVALID_INDEX),
mCornerRadiusIndex(Property::INVALID_INDEX),
mFittingMode(fittingMode),
mFlags(0),
mResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
mType(type),
- mNeedCornerRadius(false)
+ mNeedCornerRadius(false),
+ mNeedBorderline(false)
{
}
Transform mTransform;
Vector4 mMixColor;
Size mControlSize;
+ float mBorderlineWidth;
+ Vector4 mBorderlineColor;
+ float mBorderlineOffset;
Vector4 mCornerRadius;
float mCornerRadiusPolicy;
int mDepthIndex;
Property::Index mMixColorIndex;
+ Property::Index mBorderlineWidthIndex;
+ Property::Index mBorderlineColorIndex;
+ Property::Index mBorderlineOffsetIndex;
Property::Index mCornerRadiusIndex;
FittingMode mFittingMode; //< How the contents should fit the view
int mFlags;
Toolkit::Visual::ResourceStatus mResourceStatus;
const Toolkit::Visual::Type mType;
bool mNeedCornerRadius;
+ bool mNeedBorderline;
};
} // namespace Visual
mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
}
+ if(IsBorderlineRequired())
+ {
+ mImpl->mBorderlineWidthIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_WIDTH, BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
+ mImpl->mBorderlineColorIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_COLOR, BORDERLINE_COLOR, mImpl->mBorderlineColor);
+ mImpl->mBorderlineOffsetIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_OFFSET, BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+
+ mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+ }
}
}
{
matchKey = Property::Key(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE);
}
+ else if(matchKey == BORDERLINE_WIDTH)
+ {
+ matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH);
+ }
+ else if(matchKey == BORDERLINE_COLOR)
+ {
+ matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_COLOR);
+ }
+ else if(matchKey == BORDERLINE_OFFSET)
+ {
+ matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET);
+ }
else if(matchKey == CORNER_RADIUS)
{
matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS);
value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode);
break;
}
+ case Toolkit::DevelVisual::Property::BORDERLINE_WIDTH:
+ {
+ float width;
+ if(value.Get(width))
+ {
+ mImpl->mBorderlineWidth = width;
+ }
+ break;
+ }
+ case Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
+ {
+ Vector4 color;
+ if(value.Get(color))
+ {
+ mImpl->mBorderlineColor = color;
+ }
+ break;
+ }
+ case Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
+ {
+ float offset;
+ if(value.Get(offset))
+ {
+ mImpl->mBorderlineOffset = offset;
+ }
+ break;
+ }
case Toolkit::DevelVisual::Property::CORNER_RADIUS:
{
if(value.GetType() == Property::VECTOR4)
{
mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mCornerRadiusIndex);
}
+ if(mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+ {
+ mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineWidthIndex);
+ }
+ if(mImpl->mBorderlineColorIndex != Property::INVALID_INDEX)
+ {
+ mImpl->mBorderlineColor = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mBorderlineColorIndex);
+ }
+ if(mImpl->mBorderlineOffsetIndex != Property::INVALID_INDEX)
+ {
+ mImpl->mBorderlineOffset = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineOffsetIndex);
+ }
}
DoCreatePropertyMap(map);
mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT);
map.Insert(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString);
+ map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
+ map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
+ map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+
map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius);
map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, static_cast<int>(mImpl->mCornerRadiusPolicy));
}
return !(mImpl->mCornerRadius == Vector4::ZERO) || mImpl->mNeedCornerRadius;
}
+bool Visual::Base::IsBorderlineRequired() const
+{
+ if(mImpl->mRenderer && mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+ {
+ // Update values from Renderer
+ mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineWidthIndex);
+ }
+ return !EqualsZero(mImpl->mBorderlineWidth) || mImpl->mNeedBorderline;
+}
+
void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
{
// May be overriden by derived class
Property::Index index = GetPropertyIndex(key);
if(index == Property::INVALID_INDEX)
{
- if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
+ if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_WIDTH) || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_WIDTH) ||
+ (key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_COLOR) || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_COLOR) ||
+ (key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_OFFSET) || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_OFFSET))
+ {
+ mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+ // Register borderline properties
+ mImpl->mBorderlineWidthIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_WIDTH, BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
+ mImpl->mBorderlineColorIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_COLOR, BORDERLINE_COLOR, mImpl->mBorderlineColor);
+ mImpl->mBorderlineOffsetIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_OFFSET, BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+ mImpl->mNeedBorderline = true;
+
+ index = mImpl->mRenderer.GetPropertyIndex(key);
+
+ // Change shader
+ UpdateShader();
+ }
+ else if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
{
// Register CORNER_RADIUS property
mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius);
*/
bool IsRoundedCornerRequired() const;
+ /**
+ * @brief Query whether the borderline of the visual requires to be rendered.
+ *
+ * @return Returns true if the outline is required, false otherwise.
+ */
+ bool IsBorderlineRequired() const;
+
private:
/**
* Register the mix color uniform on the Renderer and store the property index.
{
COLOR_SHADER,
COLOR_SHADER_ROUNDED_CORNER,
+ COLOR_SHADER_BORDERLINE,
+ COLOR_SHADER_ROUNDED_BORDERLINE,
COLOR_SHADER_BLUR_EDGE,
+ COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE,
BORDER_SHADER,
BORDER_SHADER_ANTI_ALIASING,
- GRADIENT_SHADER_LINEAR_USER_SPACE,
GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
- GRADIENT_SHADER_RADIAL_USER_SPACE,
- GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
- GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER,
- GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+ GRADIENT_SHADER_LINEAR_BOUNDING_BOX_BORDERLINE,
+ GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_BORDERLINE,
+ GRADIENT_SHADER_LINEAR_USER_SPACE,
+ GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
+ GRADIENT_SHADER_LINEAR_USER_SPACE_BORDERLINE,
+ GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_BORDERLINE,
+ GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER,
+ GRADIENT_SHADER_RADIAL_BOUNDING_BOX_BORDERLINE,
+ GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_BORDERLINE,
+ GRADIENT_SHADER_RADIAL_USER_SPACE,
+ GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+ GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
+ GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
IMAGE_SHADER,
IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
IMAGE_SHADER_ROUNDED_CORNER,
+ IMAGE_SHADER_BORDERLINE,
+ IMAGE_SHADER_ROUNDED_BORDERLINE,
NINE_PATCH_SHADER,
NINE_PATCH_MASK_SHADER,
TEXT_SHADER_MULTI_COLOR_TEXT,
break;
}
case VisualUrl::JSON:
+ case VisualUrl::RIVE:
{
visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
break;
break;
}
case VisualUrl::JSON:
+ case VisualUrl::RIVE:
{
visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl);
break;
// Fitting mode
const char* const VISUAL_FITTING_MODE("visualFittingMode");
+// Border line
+const char* const BORDERLINE_WIDTH("borderlineWidth");
+const char* const BORDERLINE_COLOR("borderlineColor");
+const char* const BORDERLINE_OFFSET("borderlineOffset");
+
// Corner radius
const char* const CORNER_RADIUS("cornerRadius");
const char* const CORNER_RADIUS_POLICY("cornerRadiusPolicy");
// Color visual
-const char* const RENDER_IF_TRANSPARENT_NAME("renderIfTransparent");
const char* const BLUR_RADIUS_NAME("blurRadius");
// Image visual
// Fitting mode
extern const char* const VISUAL_FITTING_MODE;
+// Border line
+extern const char* const BORDERLINE_WIDTH;
+extern const char* const BORDERLINE_COLOR;
+extern const char* const BORDERLINE_OFFSET;
+
// Corner radius
extern const char* const CORNER_RADIUS;
extern const char* const CORNER_RADIUS_POLICY;
// Color visual
-extern const char* const RENDER_IF_TRANSPARENT_NAME;
extern const char* const BLUR_RADIUS_NAME;
// Image visual
char GIF[4] = {'f', 'i', 'g', '.'};
char WEBP[5] = {'p', 'b', 'e', 'w', '.'};
char JSON[5] = {'n', 'o', 's', 'j', '.'};
+ char RIVE[4] = {'v', 'i', 'r', '.'};
unsigned int svgScore = 0;
unsigned int gifScore = 0;
unsigned int webpScore = 0;
unsigned int jsonScore = 0;
+ unsigned int riveScore = 0;
int index = count;
while(--index >= 0)
{
return VisualUrl::JSON;
}
}
+ if((offsetFromEnd < sizeof(RIVE)) && (currentChar == RIVE[offsetFromEnd]))
+ {
+ // early out if RIVE as can't be used in N patch for now
+ if(++riveScore == sizeof(RIVE))
+ {
+ return VisualUrl::RIVE;
+ }
+ }
switch(state)
{
case SUFFIX:
SVG,
GIF,
WEBP,
- JSON
+ JSON,
+ RIVE
};
enum ProtocolType
#endif
/**
- * @brief Replace the background visual if it's a color visual with the renderIfTransparent property set as required.
- * @param[in] controlImpl The control implementation
- * @param[in] renderIfTransaparent Whether we should render if the color is transparent
- */
-void ChangeBackgroundColorVisual(Control& controlImpl, bool renderIfTransparent)
-{
- Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
-
- Toolkit::Visual::Base backgroundVisual = controlDataImpl.GetVisual(Toolkit::Control::Property::BACKGROUND);
- if(backgroundVisual && backgroundVisual.GetType() == Toolkit::Visual::COLOR)
- {
- Property::Map map;
- backgroundVisual.CreatePropertyMap(map);
-
- // Only change it if it's a color visual
- map[Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT] = renderIfTransparent;
- controlImpl.SetBackground(map);
- }
-}
-
-/**
* @brief Creates a clipping renderer if required.
* (EG. If no renders exist and clipping is enabled).
* @param[in] controlImpl The control implementation.
int clippingMode = ClippingMode::DISABLED;
if(self.GetProperty(Actor::Property::CLIPPING_MODE).Get(clippingMode))
{
- switch(clippingMode)
- {
- case ClippingMode::CLIP_CHILDREN:
- {
- if(self.GetRendererCount() == 0u)
- {
- Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
- if(controlDataImpl.mVisuals.Empty())
- {
- controlImpl.SetBackgroundColor(Color::TRANSPARENT);
- }
- else
- {
- // We have visuals, check if we've set the background and re-create it to
- // render even if transparent (only if it's a color visual)
- ChangeBackgroundColorVisual(controlImpl, true);
- }
- }
- break;
- }
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
- case ClippingMode::DISABLED:
- case ClippingMode::CLIP_TO_BOUNDING_BOX:
- {
- // If we have a background visual, check if it's a color visual and remove the render if transparent flag
- ChangeBackgroundColorVisual(controlImpl, false);
- break;
- }
+ if(clippingMode == ClippingMode::CLIP_CHILDREN && controlDataImpl.mVisuals.Empty() && self.GetRendererCount() == 0u)
+ {
+ controlImpl.SetBackgroundColor(Color::TRANSPARENT);
}
}
}
map[Toolkit::Visual::Property::TYPE] = Toolkit::Visual::COLOR;
map[Toolkit::ColorVisual::Property::MIX_COLOR] = color;
- bool renderIfTransparent = false;
- int clippingMode = ClippingMode::DISABLED;
- if((Self().GetProperty(Actor::Property::CLIPPING_MODE).Get(clippingMode)) &&
- (clippingMode == ClippingMode::CLIP_CHILDREN))
- {
- // If clipping-mode is set to CLIP_CHILDREN, then force visual to add the render even if transparent
- map[Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT] = true;
- renderIfTransparent = true;
- }
-
Toolkit::Visual::Base visual = mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
if(visual && visual.GetType() == Toolkit::Visual::COLOR)
{
- Property::Map visualMap;
- visual.CreatePropertyMap(visualMap);
-
- Property::Value* renderValue = visualMap.Find(Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT);
- Property::Value* colorValue = visualMap.Find(Toolkit::ColorVisual::Property::MIX_COLOR);
- if(renderValue && colorValue)
- {
- if((renderValue->Get<bool>() == true || colorValue->Get<Vector4>().a > 0.0f) && (renderIfTransparent || color.a > 0.0f))
- {
- // Update background color only
- mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelColorVisual::Action::UPDATE_PROPERTY, map);
- return;
- }
- }
+ // Update background color only
+ mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelColorVisual::Action::UPDATE_PROPERTY, map);
+ return;
}
SetBackground(map);
if(type)
{
auto typeName = type.GetName();
- DevelControl::AppendAccessibilityAttribute(Self(), "t", typeName);
+ DevelControl::AppendAccessibilityAttribute(Self(), "class", typeName);
}
-
- if(Accessibility::IsUp())
- mImpl->AccessibilityRegister();
}
void Control::OnInitialize()
// The clipping renderer is only created if required.
CreateClippingRenderer(*this);
-
- // Request to be laid out when the control is connected to the Scene.
- // Signal that a Relayout may be needed
- if(Accessibility::IsUp())
- {
- mImpl->AccessibilityRegister();
- }
}
void Control::OnSceneDisconnection()
{
- if(Accessibility::IsUp())
- {
- mImpl->AccessibilityDeregister(true);
- }
mImpl->OnSceneDisconnection();
}
JUSTIFY_CENTER, ///< Items are positioned at the center of the container @SINCE_1_1.35
JUSTIFY_FLEX_END, ///< Items are positioned at the end of the container @SINCE_1_1.35
JUSTIFY_SPACE_BETWEEN, ///< Items are positioned with equal space between the lines @SINCE_1_1.35
- JUSTIFY_SPACE_AROUND ///< Items are positioned with equal space before, between, and after the lines @SINCE_1_1.35
+ JUSTIFY_SPACE_AROUND, ///< Items are positioned with equal space before, and after the lines @SINCE_1_1.35
+ JUSTIFY_SPACE_EVENLY ///< Items are positioned with equal space before, between, and after the lines @SINCE_2_0.29
};
/**
{
const unsigned int TOOLKIT_MAJOR_VERSION = 2;
const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 23;
+const unsigned int TOOLKIT_MICRO_VERSION = 29;
const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
| JUSTIFY_CENTER | Items are positioned at the center of the container |
| JUSTIFY_FLEX_END | Items are positioned at the end of the container |
| JUSTIFY_SPACE_BETWEEN | Items are positioned with equal space between the lines |
-| JUSTIFY_SPACE_AROUND | Items are positioned with equal space before, between, and after the lines |
+| JUSTIFY_SPACE_AROUND | Items are positioned with equal space before, and after the lines |
+| JUSTIFY_SPACE_EVENLY | Items are positioned with equal space before, between, and after the lines |
### Usage
Name: dali2-toolkit
Summary: Dali 3D engine Toolkit
-Version: 2.0.23
+Version: 2.0.29
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT