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;
#define DALI_TOOLKIT_ADAPTOR_IMPL_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.
void AddWindow( Internal::Adaptor::SceneHolder* window );
void RemoveWindow( Internal::Adaptor::SceneHolder* window );
- void RegisterProcessor( Integration::Processor& processor );
- void UnregisterProcessor( Integration::Processor& processor );
+ void RegisterProcessor( Integration::Processor& processor, bool postProcessor = false);
+ void UnregisterProcessor( Integration::Processor& processor, bool postProcessor = false);
void SetApplication( Dali::TestApplication& testApplication );
/*
- * 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.
}
}
-void Adaptor::RegisterProcessor( Integration::Processor& processor )
+void Adaptor::RegisterProcessor( Integration::Processor& processor, bool postProcessor )
{
Integration::Core& core = mTestApplication->GetCore();
- core.RegisterProcessor( processor );
+ core.RegisterProcessor( processor, postProcessor );
}
-void Adaptor::UnregisterProcessor( Integration::Processor& processor )
+void Adaptor::UnregisterProcessor( Integration::Processor& processor, bool postProcessor )
{
Integration::Core& core = mTestApplication->GetCore();
- core.UnregisterProcessor( processor );
+ core.UnregisterProcessor( processor, postProcessor );
}
void Adaptor::SetApplication( Dali::TestApplication& testApplication )
return *gLogFactory;
}
-void Adaptor::RegisterProcessor( Integration::Processor& processor )
+void Adaptor::RegisterProcessor( Integration::Processor& processor, bool postProcessor)
{
- mImpl->RegisterProcessor( processor );
+ mImpl->RegisterProcessor( processor, postProcessor );
}
-void Adaptor::UnregisterProcessor( Integration::Processor& processor )
+void Adaptor::UnregisterProcessor( Integration::Processor& processor, bool postProcessor)
{
- mImpl->UnregisterProcessor( processor );
+ mImpl->UnregisterProcessor( processor, postProcessor );
}
} // namespace Dali
/*
- * 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++;
{
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
/*
- * 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";
bool gAnimationFinishedSignalFired = false;
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;
+}
END_TEST;
}
+
+
+int utcDaliTextEditorGetHeightForWidthDoesNotChangeLineCountScrollingCase(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" utcDaliTextEditorGetHeightForWidthDoesNotChangeLineCountScrollingCase ");
+
+ 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( 100.f, 100.f ) );
+ //Set text longer than width of textEditor
+ textEditor.SetProperty( TextEditor::Property::TEXT, "TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ");
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+
+ //Failed case is the GetHeightForWidth change LineCount then the scrollor will not arrive to latest line
+ //GetHeightForWidth is a retrieval method which should not modify object
+ lineCountBefore = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ textEditor.GetHeightForWidth(200.f);
+
+ //This is to simulate focus into text editor after calling GetHeightForWidth
+ //Create a tap event to touch the text editor.
+ TestGenerateTap( application, 18.0f, 25.0f );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCountAfter = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+ //The LineCount must not be changed when calling GetHeightForWidth.
+ DALI_TEST_EQUALS( lineCountAfter , lineCountBefore, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int utcDaliTextEditorGetHeightForWidthDoesNotChangeLineCountLineWrapCharCase(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" utcDaliTextEditorGetHeightForWidthDoesNotChangeLineCountLineWrapCharCase ");
+
+ 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( 50.f, 100.f ) );
+ //Set text longer than width of textEditor
+ textEditor.SetProperty( TextEditor::Property::TEXT, "qwertyuiopasdfghjklzxcvbnm\n");
+ //Set line wrap mode Character
+ textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, "CHARACTER");
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+
+ //Failed case is the GetHeightForWidth change LineCount which make position of cursor invalid in TextEditor
+ //GetHeightForWidth is a retrieval method which should not modify object
+ lineCountBefore = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ textEditor.GetHeightForWidth(200.f);
+
+ //This is to simulate focus into text editor after calling GetHeightForWidth
+ //Create a tap event to touch the text editor.
+ TestGenerateTap( application, 18.0f, 25.0f );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCountAfter = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+ //The LineCount must not be changed when calling GetHeightForWidth.
+ DALI_TEST_EQUALS( lineCountAfter , lineCountBefore, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountScrollingCase(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountScrollingCase ");
+
+ 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( 100.f, 100.f ) );
+ //Set text longer than width of textEditor
+ textEditor.SetProperty( TextEditor::Property::TEXT, "TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ");
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+
+ //Failed case is the GetNaturalSize change LineCount then the scrollor will not arrive to latest line
+ //GetNaturalSize is a retrieval method which should not modify object
+ lineCountBefore = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ textEditor.GetNaturalSize();
+
+ //This is to simulate focus into text editor after calling GetNaturalSize
+ //Create a tap event to touch the text editor.
+ TestGenerateTap( application, 18.0f, 25.0f );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCountAfter = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+ //The LineCount must not be changed when calling GetNaturalSize.
+ DALI_TEST_EQUALS( lineCountAfter , lineCountBefore, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountLineWrapCharCase(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountLineWrapCharCase ");
+
+ 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( 50.f, 100.f ) );
+ //Set text longer than width of textEditor
+ textEditor.SetProperty( TextEditor::Property::TEXT, "qwertyuiopasdfghjklzxcvbnm\n");
+ //Set line wrap mode Character
+ textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, "CHARACTER");
+
+ application.GetScene().Add( textEditor );
+
+ application.SendNotification();
+ application.Render();
+
+ //Failed case is the GetNaturalSize change LineCount which make position of cursor invalid in TextEditor
+ //GetNaturalSize is a retrieval method which should not modify object
+ lineCountBefore = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ textEditor.GetNaturalSize( );
+
+ //This is to simulate focus into text editor after calling GetNaturalSize
+ //Create a tap event to touch the text editor.
+ TestGenerateTap( application, 18.0f, 25.0f );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCountAfter = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+ //The LineCount must not be changed when calling GetNaturalSize.
+ DALI_TEST_EQUALS( lineCountAfter , lineCountBefore, TEST_LOCATION );
+
+ END_TEST;
+}
\ No newline at end of file
IF(NOT ANDROID)
ADD_EXECUTABLE(${SHADER_GENERATOR_NAME} ${SHADER_GENERATOR_SOURCES})
- INSTALL(TARGETS ${SHADER_GENERATOR_NAME} DESTINATION ${BINDIR})
+ 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()
mChanged = true;
}
-void CanvasView::Process()
+void CanvasView::Process(bool postProcessor)
{
if(!mCanvasRenderer)
{
/**
* @copydoc Dali::Integration::Processor::Process()
*/
- void Process() override;
+ void Process(bool postProcessor) override;
private:
/**
{
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())
{
{
namespace Text
{
-Vector3 Controller::Relayouter::GetNaturalSize(Controller& controller)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
- Vector3 naturalSize;
- // Make sure the model is up-to-date before layouting
- controller.ProcessModifyEvents();
+Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask, bool restoreLinesAndGlyphPositions)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->CalculateLayoutSizeOnRequiredControllerSize\n");
+ Size calculatedLayoutSize;
Controller::Impl& impl = *controller.mImpl;
ModelPtr& model = impl.mModel;
VisualModelPtr& visualModel = model->mVisualModel;
- if(impl.mRecalculateNaturalSize)
+
+ // Store the pending operations mask so that it can be restored later on with no modifications made on it
+ // while getting the natural size were reflected on the original mask.
+ OperationsMask operationsPendingBackUp = static_cast<OperationsMask>(impl.mOperationsPending);
+
+ // This is a hotfix for side effect on Scrolling, LineWrap and Invalid position of cursor in TextEditor after calling CalculateLayoutSizeOnRequiredControllerSize.
+ // The number of lines and glyph-positions inside visualModel have been changed by calling DoRelayout with requestedControllerSize.
+ // Store the mLines and mGlyphPositions from visualModel so that they can be restored later on with no modifications made on them.
+ //TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel, and then blah, blah, etc.
+ Vector<LineRun> linesBackup = visualModel->mLines;
+ Vector<Vector2> glyphPositionsBackup = visualModel->mGlyphPositions;
+
+ // Operations that can be done only once until the text changes.
+ const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
+ GET_SCRIPTS |
+ VALIDATE_FONTS |
+ GET_LINE_BREAKS |
+ BIDI_INFO |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS);
+
+ // Set the update info to relayout the whole text.
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+ textUpdateInfo.mParagraphCharacterIndex = 0u;
+ textUpdateInfo.mRequestedNumberOfCharacters = model->mLogicalModel->mText.Count();
+
+ // Make sure the model is up-to-date before layouting
+ impl.UpdateModel(onlyOnceOperations);
+
+ // Get a reference to the pending operations member
+ OperationsMask& operationsPending = impl.mOperationsPending;
+
+ // Layout the text for the new width.
+ operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask);
+
+ // Store the actual control's size to restore later.
+ const Size actualControlSize = visualModel->mControlSize;
+
+ DoRelayout(controller,
+ requestedControllerSize,
+ static_cast<OperationsMask>(onlyOnceOperations |
+ requestedOperationsMask),
+ calculatedLayoutSize);
+
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ textUpdateInfo.Clear();
+ textUpdateInfo.mClearAll = true;
+
+ // Restore the actual control's size.
+ visualModel->mControlSize = actualControlSize;
+ // Restore the previously backed-up pending operations' mask without the only once operations.
+ impl.mOperationsPending = static_cast<OperationsMask>(operationsPendingBackUp & ~onlyOnceOperations);
+
+ // Restore the previously backed-up mLines and mGlyphPositions from visualModel.
+ if(restoreLinesAndGlyphPositions)
{
- // Store the pending operations mask so that it can be restored later on with no modifications made on it
- // while getting the natural size were reflected on the original mask.
- OperationsMask operationsPendingBackUp = static_cast<OperationsMask>(impl.mOperationsPending);
- // Operations that can be done only once until the text changes.
- const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
- GET_SCRIPTS |
- VALIDATE_FONTS |
- GET_LINE_BREAKS |
- BIDI_INFO |
- SHAPE_TEXT |
- GET_GLYPH_METRICS);
+ visualModel->mLines = linesBackup;
+ visualModel->mGlyphPositions = glyphPositionsBackup;
+ }
- // Set the update info to relayout the whole text.
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
- textUpdateInfo.mParagraphCharacterIndex = 0u;
- textUpdateInfo.mRequestedNumberOfCharacters = model->mLogicalModel->mText.Count();
+ return calculatedLayoutSize;
+}
- // Make sure the model is up-to-date before layouting
- impl.UpdateModel(onlyOnceOperations);
- // Get a reference to the pending operations member
- OperationsMask& operationsPending = impl.mOperationsPending;
+Vector3 Controller::Relayouter::GetNaturalSize(Controller& controller)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
+ Vector3 naturalSizeVec3;
- // Layout the text for the new width.
- operationsPending = static_cast<OperationsMask>(operationsPending | LAYOUT | REORDER);
+ // Make sure the model is up-to-date before layouting
+ controller.ProcessModifyEvents();
+
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+
+ if(impl.mRecalculateNaturalSize)
+ {
+ Size naturalSize;
- // Store the actual control's size to restore later.
- const Size actualControlSize = visualModel->mControlSize;
+ // Layout the text for the new width.
+ OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT | REORDER);
+ Size sizeMaxWidthAndMaxHeight = Size(MAX_FLOAT, MAX_FLOAT);
- DoRelayout(controller,
- Size(MAX_FLOAT, MAX_FLOAT),
- static_cast<OperationsMask>(onlyOnceOperations |
- LAYOUT | REORDER),
- naturalSize.GetVectorXY());
+ naturalSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeMaxWidthAndMaxHeight, requestedOperationsMask, true);
// Stores the natural size to avoid recalculate it again
// unless the text/style changes.
- visualModel->SetNaturalSize(naturalSize.GetVectorXY());
+ visualModel->SetNaturalSize(naturalSize);
+ naturalSizeVec3 = naturalSize;
impl.mRecalculateNaturalSize = false;
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.Clear();
- textUpdateInfo.mClearAll = true;
-
- // Restore the actual control's size.
- visualModel->mControlSize = actualControlSize;
- // Restore the previously backed-up pending operations' mask without the only once operations.
- impl.mOperationsPending = static_cast<OperationsMask>(operationsPendingBackUp & ~onlyOnceOperations);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSizeVec3.x, naturalSizeVec3.y, naturalSizeVec3.z);
}
else
{
- naturalSize = visualModel->GetNaturalSize();
+ naturalSizeVec3 = visualModel->GetNaturalSize();
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSizeVec3.x, naturalSizeVec3.y, naturalSizeVec3.z);
}
- naturalSize.x = ConvertToEven(naturalSize.x);
- naturalSize.y = ConvertToEven(naturalSize.y);
+ naturalSizeVec3.x = ConvertToEven(naturalSizeVec3.x);
+ naturalSizeVec3.y = ConvertToEven(naturalSizeVec3.y);
- return naturalSize;
+ return naturalSizeVec3;
}
bool Controller::Relayouter::CheckForTextFit(Controller& controller, float pointSize, const Size& layoutSize)
float Controller::Relayouter::GetHeightForWidth(Controller& controller, float width)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", &controller, width);
+
// Make sure the model is up-to-date before layouting
controller.ProcessModifyEvents();
TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
Size layoutSize;
+
if(fabsf(width - visualModel->mControlSize.width) > Math::MACHINE_EPSILON_1000 ||
textUpdateInfo.mFullRelayoutNeeded ||
textUpdateInfo.mClearAll)
{
- // Store the pending operations mask so that it can be restored later on with no modifications made on it
- // while getting the natural size were reflected on the original mask.
- OperationsMask operationsPendingBackUp = static_cast<OperationsMask>(impl.mOperationsPending);
- // Operations that can be done only once until the text changes.
- const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
- GET_SCRIPTS |
- VALIDATE_FONTS |
- GET_LINE_BREAKS |
- BIDI_INFO |
- SHAPE_TEXT |
- GET_GLYPH_METRICS);
-
- // Set the update info to relayout the whole text.
- textUpdateInfo.mParagraphCharacterIndex = 0u;
- textUpdateInfo.mRequestedNumberOfCharacters = model->mLogicalModel->mText.Count();
-
- // Make sure the model is up-to-date before layouting
- impl.UpdateModel(onlyOnceOperations);
-
- // Get a reference to the pending operations member
- OperationsMask& operationsPending = impl.mOperationsPending;
// Layout the text for the new width.
- operationsPending = static_cast<OperationsMask>(operationsPending | LAYOUT);
+ OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT);
+ Size sizeRequestedWidthAndMaxHeight = Size(width, MAX_FLOAT);
- // Store the actual control's width.
- const float actualControlWidth = visualModel->mControlSize.width;
+ // Skip restore, because if GetHeightForWidth called before rendering and layouting then visualModel->mControlSize will be zero which will make LineCount zero.
+ // 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;
- DoRelayout(controller,
- Size(width, MAX_FLOAT),
- static_cast<OperationsMask>(onlyOnceOperations |
- LAYOUT),
- layoutSize);
-
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.Clear();
- textUpdateInfo.mClearAll = true;
+ layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask, restoreLinesAndGlyphPositions);
- // Restore the actual control's width.
- visualModel->mControlSize.width = actualControlWidth;
- // Restore the previously backed-up pending operations' mask without the only once operations.
- impl.mOperationsPending = static_cast<OperationsMask>(operationsPendingBackUp & ~onlyOnceOperations);
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
}
else
* @param[in] controlSize The control size
*/
static void CalculateVerticalOffset(Controller& controller, const Size& controlSize);
+
+ /**
+ * @brief Calculates the layout size of control according to @p requestedControllerSize and @p requestedOperationsMask
+ *
+ * GetNaturalSize() and GetHeightForWidth() calls this method.
+ *
+ * @param[in] controller The controller to calcualte size on it.
+ * @param[in] requestedControllerSize The requested size of controller to calcualte layout size on it.
+ * @param[in] requestedOperationsMask The requested operations-mask to calcualte layout size according to it.
+ * @param[in] restoreLinesAndGlyphPositions whether to restore lines and glyph-positions to status before requesting calculation on size.
+ *
+ * @return The calculated layout-size.
+ */
+ static Size CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask, bool restoreLinesAndGlyphPositions);
+
};
} // namespace Text
}
}
-void VectorAnimationManager::Process()
+void VectorAnimationManager::Process(bool postProcessor)
{
for(auto&& iter : mEventCallbacks)
{
/**
* @copydoc Dali::Integration::Processor::Process()
*/
- void Process() override;
+ void Process(bool postProcessor) override;
private:
// Undefined
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);
bool VectorAnimationTask::Rasterize()
{
bool stopped = false;
- uint32_t currentFrame;
+ uint32_t currentFrame, droppedFrames = 0;
{
ConditionalWait::ScopedLock lock(mConditionalWait);
// The task will be destroyed. We don't need rasterization.
return false;
}
+ droppedFrames = mDroppedFrames;
}
ApplyAnimationData();
if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber)
{
- mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
+ mCurrentFrame = mForward ? mCurrentFrame + droppedFrames + 1 : mCurrentFrame - droppedFrames - 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)
{
+ uint32_t droppedFrames = 0;
+
// 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;
+ }
+ else if(mNextFrameStartTime < current)
{
+ 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));
+ }
+
+ {
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+ mDroppedFrames = droppedFrames;
+ }
+
mNextFrameStartTime = current;
}
+
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
UnregisterProcessor();
}
-void SvgRasterizeThread::Process()
+void SvgRasterizeThread::Process(bool postProcessor)
{
ApplyRasterizedSVGToSampler();
}
/**
* @copydoc Dali::Integration::Processor::Process()
*/
- void Process() override;
+ void Process(bool postProcessor) override;
private:
/**