* [Building and executing test cases](#building-and-executing-test-cases)
* [2. GBS Builds](#2-gbs-builds)
* [DEBUG Builds](#debug-builds)
- * [3. Building for Emscripten](#3-building-for-emscripten)
- * [Setup dali-env & build dali-core](#setup-dali-env--build-dali-core)
- * [Build the minimal dali-adaptor](#build-the-minimal-dali-adaptor)
- * [Using the Javascript Build](#using-the-javascript-build)
# Build Instructions
$ gbs build -A [TARGET_ARCH] --define "%enable_debug 1"
-## 3. Building for Emscripten
-
-Currently the build for emscripten uses a minimal adaptor which does not support dali-toolkit.
-
-### Setup dali-env & build dali-core
-
- The build requires the Emscripten SDK, this is installed automatically by running dali_env with the correct parameters.
- dali_env is part of the dali-core repository.
- Please see the README within dali-core to setup dali_env and build dali-core.
-
-### Build the minimal dali-adaptor
-
- Use the build.sh script build adaptor.
- This uses emscriptens emcc to compile byte code to javascript (full OpenGL ES support with stb-image loading library and cpp bindings).
- Note: Please view the build.sh script for debug build options.
-
- $ # cd ./build/emscripten
- $ # ./build.sh
-
-### Using the Javascript Build
-
- The build will create 1 main Javascript artifact, and its html counterpart; dali-emscripten.js
-
- This is required by any dali JS app, and must be located in the same directory as the app JS in order for the browser to find it.
-
- After the build, the necessary artifacts (which include dali-wrapper.js) will be placed in the dali-env directory under opt/share/emscripten:
-
- dali-env/opt/share/emscripten
-
- If dali-demo is built, any JS examples will also be placed in this directory, so they are ready to run.
bool useElapsedTime = true;
bool updateRequired = true;
+ uint64_t timeToSleepUntil = 0;
+ int extraFramesDropped = 0;
- while( UpdateRenderReady( useElapsedTime, updateRequired ) )
+ while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
{
LOG_UPDATE_RENDER_TRACE;
if( useElapsedTime )
{
// If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
- // Round up if remainder is more than half the default frame time
- noOfFramesSinceLastUpdate = ( timeSinceLastFrame + mDefaultHalfFrameNanoseconds) / mDefaultFrameDurationNanoseconds;
+ noOfFramesSinceLastUpdate += extraFramesDropped;
+
frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
}
LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
mCore.Render( renderStatus );
AddPerformanceMarker( PerformanceInterface::RENDER_END );
- mRenderHelper.PostRender();
+ if( renderStatus.NeedsPostRender() )
+ {
+ mRenderHelper.PostRender();
+ }
// Trigger event thread to request Update/Render thread to sleep if update not required
if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
// FRAME TIME
//////////////////////////////
+ extraFramesDropped = 0;
+
+ if (timeToSleepUntil == 0)
+ {
+ // If this is the first frame after the thread is initialized or resumed, we
+ // use the actual time the current frame starts from to calculate the time to
+ // sleep until the next frame.
+ timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
+ }
+ else
+ {
+ // Otherwise, always use the sleep-until time calculated in the last frame to
+ // calculate the time to sleep until the next frame. In this way, if there is
+ // any time gap between the current frame and the next frame, or if update or
+ // rendering in the current frame takes too much time so that the specified
+ // sleep-until time has already passed, it will try to keep the frames syncing
+ // by shortening the duration of the next frame.
+ timeToSleepUntil += mDefaultFrameDurationNanoseconds;
+
+ // Check the current time at the end of the frame
+ uint64_t currentFrameEndTime = 0;
+ TimeService::GetNanoseconds( currentFrameEndTime );
+ while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
+ {
+ // We are more than one frame behind already, so just drop the next frames
+ // until the sleep-until time is later than the current time so that we can
+ // catch up.
+ timeToSleepUntil += mDefaultFrameDurationNanoseconds;
+ extraFramesDropped++;
+ }
+ }
+
// Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
- TimeService::SleepUntil( currentFrameStartTime + mDefaultFrameDurationNanoseconds );
+ TimeService::SleepUntil( timeToSleepUntil );
}
// Inform core of context destruction & shutdown EGL
mEnvironmentOptions.UnInstallLogFunction();
}
-bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired )
+bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
{
useElapsedTime = true;
LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
+ // Reset the time when the thread is waiting, so the sleep-until time for
+ // the first frame after resuming should be based on the actual start time
+ // of the first frame.
+ timeToSleepUntil = 0;
+
mUpdateRenderThreadWaitCondition.Wait( updateLock );
if( ! mUseElapsedTimeAfterWait )
/**
* Called by the Update/Render Thread which ensures a wait if required.
*
- * @param[out] useElapsedTime If true when returned, then the actual elapsed time will be used for animation.
- * If false when returned, then there should NOT be any animation progression in the next Update.
- * @param[in] updateRequired Whether another update is required.
+ * @param[out] useElapsedTime If true when returned, then the actual elapsed time will be used for animation.
+ * If false when returned, then there should NOT be any animation progression in the next Update.
+ * @param[in] updateRequired Whether another update is required.
+ * @param[out] timeToSleepUntil The time remaining in nanoseconds to keep the thread sleeping before resuming.
* @return false, if the thread should stop.
*/
- bool UpdateRenderReady( bool& useElapsedTime, bool updateRequired );
+ bool UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil );
/**
* Checks to see if the surface needs to be replaced.
/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
mRenderRefreshRate( 1 ),
mGlesCallAccumulate( false ),
mMultiSamplingLevel( 0 ),
+ mMaxTextureSize( 0 ),
mLogFunction( NULL )
{
ParseEnvironmentOptions();
return mMultiSamplingLevel;
}
+unsigned int EnvironmentOptions::GetMaxTextureSize() const
+{
+ return mMaxTextureSize;
+}
+
bool EnvironmentOptions::PerformanceServerRequired() const
{
return ( ( GetPerformanceStatsLoggingOptions() > 0) ||
mMultiSamplingLevel = multiSamplingLevel;
}
}
+
+ int maxTextureSize( 0 );
+ if( GetIntegerEnvironmentVariable( DALI_ENV_MAX_TEXTURE_SIZE, maxTextureSize ) )
+ {
+ if( maxTextureSize > 0 )
+ {
+ mMaxTextureSize = maxTextureSize;
+ }
+ }
}
} // Adaptor
#define __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H__
/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
*/
unsigned int GetMultiSamplingLevel() const;
+ /**
+ * @return The maximum texture size
+ */
+ unsigned int GetMaxTextureSize() const;
+
private: // Internal
/**
unsigned int mRenderRefreshRate; ///< render refresh rate
bool mGlesCallAccumulate; ///< Whether or not to accumulate gles call statistics
unsigned int mMultiSamplingLevel; ///< The number of samples required in multisample buffers
+ unsigned int mMaxTextureSize; ///< The maximum texture size that GL can handle
Dali::Integration::Log::LogFunction mLogFunction;
#define __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H__
/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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 DALI_ENV_MULTI_SAMPLING_LEVEL "DALI_MULTI_SAMPLING_LEVEL"
+#define DALI_ENV_MAX_TEXTURE_SIZE "DALI_MAX_TEXTURE_SIZE"
+
} // namespace Adaptor
} // namespace Internal
mThreadSynchronization.RenderFinished();
// Perform any post-render operations
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - PostRender()\n");
- mRenderHelper.PostRender();
+ if( renderStatus.NeedsPostRender() )
+ {
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - PostRender()\n");
+ mRenderHelper.PostRender();
+ }
}
}
Integration::UpdateStatus status;
mCore.Update( 0.0f, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, status );
- Integration::RenderStatus renderStatus;
- mRenderHelper.PreRender();
- mCore.Render( renderStatus );
- mRenderHelper.PostRender();
+ Render();
}
}
if( mState != State::STOPPED )
{
mRenderHelper.ConsumeEvents();
- mRenderHelper.PreRender();
-
- Integration::RenderStatus renderStatus;
- AddPerformanceMarker( PerformanceInterface::RENDER_START );
- mCore.Render( renderStatus );
- AddPerformanceMarker( PerformanceInterface::RENDER_END );
- mRenderHelper.PostRender();
+ const bool needsUpdate = Render();
- if( ! keepUpdatingStatus &&
- ! renderStatus.NeedsUpdate() )
+ if( !keepUpdatingStatus && !needsUpdate )
{
ChangeState( State::SLEEPING );
}
mRenderHelper.ShutdownEgl();
}
+bool SingleThreadController::Render()
+{
+ mRenderHelper.PreRender();
+
+ Integration::RenderStatus renderStatus;
+ AddPerformanceMarker( PerformanceInterface::RENDER_START );
+ mCore.Render( renderStatus );
+ AddPerformanceMarker( PerformanceInterface::RENDER_END );
+
+ if( renderStatus.NeedsPostRender() )
+ {
+ mRenderHelper.PostRender();
+ }
+
+ return renderStatus.NeedsUpdate();
+}
+
} // namespace Adaptor
} // namespace Internal
*/
void StopRendering();
+ /**
+ * Runs render (along with pre & post steps as required).
+ * @return True if an update is required.
+ */
+ bool Render();
+
private:
Dali::Timer mTimer; ///< Ensures an update & render is run every frame.
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
// INTERNAL INCLUDES
#include <base/thread-controller.h>
-# include <base/performance-logging/performance-interface-factory.h>
+#include <base/performance-logging/performance-interface-factory.h>
#include <base/lifecycle-observer.h>
#include <dali/devel-api/text-abstraction/font-client.h>
#include <window-impl.h>
#include <tizen-logging.h>
+#include <image-loading.h>
using Dali::TextAbstraction::FontClient;
{
Integration::SetPanGestureSmoothingAmount(mEnvironmentOptions->GetPanGestureSmoothingAmount());
}
+
+ // Set max texture size
+ if( mEnvironmentOptions->GetMaxTextureSize() > 0 )
+ {
+ Dali::SetMaxTextureSize( mEnvironmentOptions->GetMaxTextureSize() );
+ }
}
Adaptor::~Adaptor()
mEventHandler->FeedKeyEvent( keyEvent );
}
-bool Adaptor::MoveResize( const PositionSize& positionSize )
-{
- PositionSize old = mSurface->GetPositionSize();
-
- // just resize the surface. The driver should automatically resize the egl Surface (untested)
- // EGL Spec says : EGL window surfaces need to be resized when their corresponding native window
- // is resized. Implementations typically use hooks into the OS and native window
- // system to perform this resizing on demand, transparently to the client.
- mSurface->MoveResize( positionSize );
-
- if(old.width != positionSize.width || old.height != positionSize.height)
- {
- SurfaceSizeChanged(positionSize);
- }
-
- return true;
-}
-
-void Adaptor::SurfaceResized( const PositionSize& positionSize )
-{
- PositionSize old = mSurface->GetPositionSize();
-
- // Called by an application, when it has resized a window outside of Dali.
- // The EGL driver automatically detects X Window resize calls, and resizes
- // the EGL surface for us.
- mSurface->MoveResize( positionSize );
-
- if(old.width != positionSize.width || old.height != positionSize.height)
- {
- SurfaceSizeChanged(positionSize);
- }
-}
-
void Adaptor::ReplaceSurface( Any nativeWindow, RenderSurface& surface )
{
mNativeWindow = nativeWindow;
RequestUpdate();
}
-void Adaptor::SurfaceSizeChanged( const PositionSize& positionSize )
+void Adaptor::SurfaceSizeChanged( Dali::Adaptor::SurfaceSize surfaceSize )
{
// let the core know the surface size has changed
- mCore->SurfaceResized(positionSize.width, positionSize.height);
+ mCore->SurfaceResized( surfaceSize.GetWidth(), surfaceSize.GetHeight() );
mResizedSignal.Emit( mAdaptor );
}
#define __DALI_INTERNAL_ADAPTOR_IMPL_H__
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
virtual void FeedKeyEvent( KeyEvent& keyEvent );
/**
- * @copydoc AdaptorInterface::MoveResize()
- */
- virtual bool MoveResize( const PositionSize& positionSize );
-
- /**
- * @copydoc AdaptorInterface::SurfaceResized()
- */
- virtual void SurfaceResized( const PositionSize& positionSize );
-
- /**
* @copydoc AdaptorInterface::ReplaceSurface()
*/
virtual void ReplaceSurface( Any nativeWindow, RenderSurface& surface );
/**
* Informs core the surface size has changed
*/
- void SurfaceSizeChanged( const PositionSize& positionSize );
+ void SurfaceSizeChanged( Dali::Adaptor::SurfaceSize surfaceSize );
public: //AdaptorInternalServices
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
mImpl->SetStereoBase( stereoBase );
}
-void Adaptor::SurfaceSizeChanged( const PositionSize& positionSize )
+void Adaptor::SurfaceSizeChanged( SurfaceSize surfaceSize )
{
- mImpl->SurfaceSizeChanged( positionSize );
+ mImpl->SurfaceSizeChanged( surfaceSize );
}
Adaptor::Adaptor()
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
char **argv[],
const std::string& stylesheet,
Dali::Application::WINDOW_MODE windowMode,
+ const PositionSize& positionSize,
Framework::Type applicationType)
{
- ApplicationPtr application ( new Application (argc, argv, stylesheet, windowMode, applicationType ) );
+ ApplicationPtr application ( new Application (argc, argv, stylesheet, windowMode, positionSize, applicationType ) );
return application;
}
Application::Application( int* argc, char** argv[], const std::string& stylesheet,
- Dali::Application::WINDOW_MODE windowMode, Framework::Type applicationType )
+ Dali::Application::WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType )
: mInitSignal(),
mTerminateSignal(),
mPauseSignal(),
mName(),
mStylesheet( stylesheet ),
mEnvironmentOptions(),
+ mWindowPositionSize( positionSize ),
mSlotDelegate( this )
{
// Get mName from environment options
void Application::CreateWindow()
{
- PositionSize windowPosition(0, 0, 0, 0); // this will use full screen
-
- if( mCommandLineOptions->stageWidth > 0 && mCommandLineOptions->stageHeight > 0 )
- {
- // Command line options override environment options and full screen
- windowPosition = PositionSize( 0, 0, mCommandLineOptions->stageWidth, mCommandLineOptions->stageHeight );
- }
- else if( mEnvironmentOptions.GetWindowWidth() && mEnvironmentOptions.GetWindowHeight() )
+ if( mWindowPositionSize.width == 0 && mWindowPositionSize.height == 0 )
{
- // Environment options override full screen functionality if command line arguments not provided
- windowPosition = PositionSize( 0, 0, mEnvironmentOptions.GetWindowWidth(), mEnvironmentOptions.GetWindowHeight() );
+ if( mCommandLineOptions->stageWidth > 0 && mCommandLineOptions->stageHeight > 0 )
+ {
+ // Command line options override environment options and full screen
+ mWindowPositionSize.width = mCommandLineOptions->stageWidth;
+ mWindowPositionSize.height = mCommandLineOptions->stageHeight;
+ }
+ else if( mEnvironmentOptions.GetWindowWidth() && mEnvironmentOptions.GetWindowHeight() )
+ {
+ // Environment options override full screen functionality if command line arguments not provided
+ mWindowPositionSize.width = mEnvironmentOptions.GetWindowWidth();
+ mWindowPositionSize.height = mEnvironmentOptions.GetWindowHeight();
+ }
}
const std::string& windowClassName = mEnvironmentOptions.GetWindowClassName();
- mWindow = Dali::Window::New( windowPosition, mName, windowClassName, mWindowMode == Dali::Application::TRANSPARENT );
+ mWindow = Dali::Window::New( mWindowPositionSize, mName, windowClassName, mWindowMode == Dali::Application::TRANSPARENT );
// Quit the application when the window is closed
GetImplementation( mWindow ).DeleteRequestSignal().Connect( mSlotDelegate, &Application::Quit );
}
-void Application::ReplaceWindow(PositionSize windowPosition, const std::string& name)
+void Application::ReplaceWindow( const PositionSize& positionSize, const std::string& name )
{
- Dali::Window newWindow = Dali::Window::New( windowPosition, name, mWindowMode == Dali::Application::TRANSPARENT );
+ Dali::Window newWindow = Dali::Window::New( positionSize, name, mWindowMode == Dali::Application::TRANSPARENT );
Window& windowImpl = GetImplementation(newWindow);
windowImpl.SetAdaptor(*mAdaptor);
newWindow.ShowIndicator(Dali::Window::INVISIBLE);
Dali::RenderSurface* renderSurface = windowImpl.GetSurface();
Any nativeWindow = newWindow.GetNativeHandle();
- Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).SurfaceSizeChanged( windowPosition );
+ Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).SurfaceSizeChanged( Dali::Adaptor::SurfaceSize( positionSize.width, positionSize.height ) );
Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).ReplaceSurface(nativeWindow, *renderSurface);
mWindow = newWindow;
+ mWindowPositionSize = positionSize;
}
std::string Application::GetResourcePath()
#define __DALI_INTERNAL_APPLICATION_H__
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
/**
* Create a new application
- * @param[in] argc A pointer to the number of arguments
- * @param[in] argv A pointer to the argument list
- * @param[in] stylesheet The path to user defined theme file
- * @param[in] windowMode A member of Dali::Application::WINDOW_MODE
+ * @param[in] argc A pointer to the number of arguments
+ * @param[in] argv A pointer to the argument list
+ * @param[in] stylesheet The path to user defined theme file
+ * @param[in] windowMode A member of Dali::Application::WINDOW_MODE
+ * @param[in] positionSize A position and a size of the window
* @param[in] applicationType A member of Dali::Framework::Type
*/
static ApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet,
- WINDOW_MODE windowMode, Framework::Type applicationType );
+ WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType );
public:
/**
* @copydoc Dali::Application::ReplaceWindow();
*/
- void ReplaceWindow(PositionSize windowPosition, const std::string& name);
+ void ReplaceWindow( const PositionSize& positionSize, const std::string& name);
/**
* @copydoc Dali::Application::GetResourcePath();
/**
* Private Constructor
- * @param[in] argc A pointer to the number of arguments
- * @param[in] argv A pointer to the argument list
- * @param[in] stylesheet The path to user defined theme file
- * @param[in] windowMode A member of Dali::Application::WINDOW_MODE
+ * @param[in] argc A pointer to the number of arguments
+ * @param[in] argv A pointer to the argument list
+ * @param[in] stylesheet The path to user defined theme file
+ * @param[in] windowMode A member of Dali::Application::WINDOW_MODE
+ * @param[in] positionSize A position and a size of the window
+ * @param[in] applicationType A member of Dali::Framework::Type
*/
Application( int* argc, char **argv[], const std::string& stylesheet,
- WINDOW_MODE windowMode, Framework::Type applicationType );
+ WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType );
/**
* Destructor
std::string mName;
std::string mStylesheet;
EnvironmentOptions mEnvironmentOptions;
+ PositionSize mWindowPositionSize;
bool mUseRemoteSurface;
SlotDelegate< Application > mSlotDelegate;
+++ /dev/null
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-
-// INTERNAL INCLUDES
-#include "image-loading.h"
-#include "bitmap-loader-impl.h"
-
-namespace Dali
-{
-namespace Internal
-{
-
-IntrusivePtr<BitmapLoader> BitmapLoader::New(const std::string& url,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection)
-{
- IntrusivePtr<BitmapLoader> internal = new BitmapLoader( url, size, fittingMode, samplingMode, orientationCorrection );
- return internal;
-}
-
-BitmapLoader::BitmapLoader(const std::string& url,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection )
-: mPixelData(),
- mUrl(url),
- mSize( size ),
- mFittingMode( fittingMode ),
- mSamplingMode( samplingMode ),
- mOrientationCorrection( orientationCorrection )
-{
-}
-
-BitmapLoader::~BitmapLoader()
-{
-}
-
-void BitmapLoader::Load()
-{
- mPixelData = Dali::LoadImageFromFile( mUrl, mSize, mFittingMode, mSamplingMode, mOrientationCorrection );
-}
-
-bool BitmapLoader::IsLoaded()
-{
- return mPixelData ? true : false ;
-}
-
-const std::string& BitmapLoader::GetUrl() const
-{
- return mUrl;
-}
-
-Dali::PixelData BitmapLoader::GetPixelData() const
-{
- return mPixelData;
-}
-
-} // namespace Internal
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_BITMAP_LOADER_IMPL_H__
-#define __DALI_BITMAP_LOADER_IMPL_H__
-
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-#include <dali/public-api/images/pixel.h>
-#include <dali/public-api/object/base-object.h>
-#include <dali/public-api/common/intrusive-ptr.h>
-#include <dali/integration-api/bitmap.h>
-#include <dali/integration-api/resource-types.h>
-
-// INTERNAL INCLUDES
-#include <bitmap-loader.h>
-
-namespace Dali
-{
-namespace Internal
-{
-
-class BitmapLoader : public BaseObject
-{
-public:
-
- /**
- * @copydoc Dali::BitmapLoader::New
- */
- static IntrusivePtr<BitmapLoader> New( const std::string& url,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection);
-
- /**
- * Create the bitmap loader object.
- */
- BitmapLoader(const std::string& url,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection);
-
-protected:
- /**
- * Destructor
- */
- ~BitmapLoader();
-
-public:
-
- /**
- * @copydoc Dali::BitmapLoader::Load
- */
- void Load();
-
- /**
- * @copydoc Dali::BitmapLoader::IsLoaded
- */
- bool IsLoaded();
-
- /**
- * @copydoc Dali::BitmapLoader::GetUrl()
- */
- const std::string& GetUrl() const;
-
- /**
- * @copydoc Dali::BitmapLoader::GetPixelData
- */
- Dali::PixelData GetPixelData() const;
-
-private:
-
- Dali::PixelData mPixelData;
- const std::string mUrl;
- ImageDimensions mSize;
- FittingMode::Type mFittingMode;
- SamplingMode::Type mSamplingMode;
- bool mOrientationCorrection;
-
-};
-
-} // Internal
-
-
-inline Internal::BitmapLoader& GetImplementation(Dali::BitmapLoader& handle)
-{
- DALI_ASSERT_ALWAYS( handle && "handle is empty" );
-
- BaseObject& object = handle.GetBaseObject();
-
- return static_cast<Internal::BitmapLoader&>(object);
-}
-
-inline const Internal::BitmapLoader& GetImplementation(const Dali::BitmapLoader& handle)
-{
- DALI_ASSERT_ALWAYS( handle && "handle is empty" );
-
- const BaseObject& object = handle.GetBaseObject();
-
- return static_cast<const Internal::BitmapLoader&>(object);
-}
-
-} // Dali
-
-#endif // __DALI_BITMAP_LOADER_IMPL_H__
$(adaptor_common_dir)/adaptor.cpp \
$(adaptor_common_dir)/adaptor-impl.cpp \
$(adaptor_common_dir)/application-impl.cpp \
- $(adaptor_common_dir)/bitmap-loader-impl.cpp \
$(adaptor_common_dir)/clipboard-event-notifier-impl.cpp \
$(adaptor_common_dir)/command-line-options.cpp \
$(adaptor_common_dir)/drag-and-drop-detector-impl.cpp \
$(adaptor_common_dir)/orientation-impl.cpp \
$(adaptor_common_dir)/performance-logger-impl.cpp \
$(adaptor_common_dir)/physical-keyboard-impl.cpp \
+ $(adaptor_common_dir)/pixel-buffer-impl.cpp \
$(adaptor_common_dir)/shared-file.cpp \
$(adaptor_common_dir)/singleton-service-impl.cpp \
$(adaptor_common_dir)/sound-player-impl.cpp \
#define __DALI_INTERNAL_EGL_IMPLEMENTATION_H__
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
Vector<EGLint> mContextAttribs;
EGLNativeDisplayType mEglNativeDisplay;
-#ifndef EMSCRIPTEN
+
EGLNativeWindowType mEglNativeWindow;
-#endif
+
EGLNativePixmapType mCurrentEglNativePixmap;
EGLDisplay mEglDisplay;
--- /dev/null
+/*
+ * Copyright (c) 2017 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 "pixel-buffer-impl.h"
+
+// EXTERNAL INCLUDES
+#include <stdlib.h>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include "pixel-manipulation.h"
+#include "alpha-mask.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+PixelBuffer::PixelBuffer( unsigned char* buffer,
+ unsigned int bufferSize,
+ unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat )
+: mBuffer( buffer ),
+ mBufferSize( bufferSize ),
+ mWidth( width ),
+ mHeight( height ),
+ mPixelFormat( pixelFormat )
+{
+}
+
+PixelBuffer::~PixelBuffer()
+{
+ ReleaseBuffer();
+}
+
+PixelBufferPtr PixelBuffer::New( unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat )
+{
+ unsigned int bufferSize = width * height * Dali::Pixel::GetBytesPerPixel( pixelFormat );
+ unsigned char* buffer = NULL;
+ if( bufferSize > 0 )
+ {
+ buffer = static_cast<unsigned char*>( malloc ( bufferSize ) );
+ }
+ return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
+}
+
+PixelBufferPtr PixelBuffer::New( unsigned char* buffer,
+ unsigned int bufferSize,
+ unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat )
+{
+ return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
+}
+
+Dali::PixelData PixelBuffer::Convert( PixelBuffer& pixelBuffer )
+{
+ Dali::PixelData pixelData = Dali::PixelData::New( pixelBuffer.mBuffer,
+ pixelBuffer.mBufferSize,
+ pixelBuffer.mWidth,
+ pixelBuffer.mHeight,
+ pixelBuffer.mPixelFormat,
+ Dali::PixelData::FREE );
+ pixelBuffer.mBuffer = NULL;
+ pixelBuffer.mWidth = 0;
+ pixelBuffer.mHeight = 0;
+ pixelBuffer.mBufferSize = 0;
+
+ return pixelData;
+}
+
+unsigned int PixelBuffer::GetWidth() const
+{
+ return mWidth;
+}
+
+unsigned int PixelBuffer::GetHeight() const
+{
+ return mHeight;
+}
+
+Dali::Pixel::Format PixelBuffer::GetPixelFormat() const
+{
+ return mPixelFormat;
+}
+
+unsigned char* PixelBuffer::GetBuffer() const
+{
+ return mBuffer;
+}
+
+unsigned int PixelBuffer::GetBufferSize() const
+{
+ return mBufferSize;
+}
+
+Dali::PixelData PixelBuffer::CreatePixelData() const
+{
+ unsigned char* destBuffer = NULL;
+
+ if( mBufferSize > 0 )
+ {
+ destBuffer = static_cast<unsigned char*>( malloc( mBufferSize ) );
+ memcpy( destBuffer, mBuffer, mBufferSize );
+ }
+
+ Dali::PixelData pixelData = Dali::PixelData::New( destBuffer, mBufferSize,
+ mWidth, mHeight,
+ mPixelFormat,
+ Dali::PixelData::FREE );
+ return pixelData;
+}
+
+void PixelBuffer::ApplyMask( const PixelBuffer& mask )
+{
+ int byteOffset=0;
+ int bitMask=0;
+
+ Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
+
+ if( Dali::Pixel::HasAlpha( mPixelFormat ) && bitMask == 255 )
+ {
+ ApplyMaskToAlphaChannel( *this, mask );
+ }
+ else
+ {
+ PixelBufferPtr newPixelBuffer = CreateNewMaskedBuffer( *this, mask );
+ ReleaseBuffer();
+
+ // Take ownership of new buffer
+ mBuffer = newPixelBuffer->mBuffer;
+ newPixelBuffer->mBuffer = NULL;
+ mPixelFormat = newPixelBuffer->mPixelFormat;
+ mBufferSize = newPixelBuffer->mBufferSize;
+
+ // On leaving scope, newPixelBuffer will get destroyed.
+ }
+}
+
+void PixelBuffer::ReleaseBuffer()
+{
+ if( mBuffer )
+ {
+ free( mBuffer );
+ }
+}
+
+
+}// namespace Adaptor
+}// namespace Internal
+}// namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H
+#define DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <pixel-buffer.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-object.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class PixelBuffer;
+typedef IntrusivePtr<PixelBuffer> PixelBufferPtr;
+
+class PixelBuffer : public BaseObject
+{
+public:
+
+ /**
+ * @brief Create a PixelBuffer object with a pre-allocated buffer.
+ * The PixelBuffer object owns this buffer, which may be retrieved
+ * and modified using GetBuffer().
+ *
+ * @param [in] width Buffer width in pixels
+ * @param [in] height Buffer height in pixels
+ * @param [in] pixelFormat The pixel format
+ */
+ static PixelBufferPtr New( unsigned int width,
+ unsigned int height,
+ Pixel::Format pixelFormat );
+
+ /**
+ * @brief Create a PixelBuffer object. For internal use only.
+ *
+ * @param [in] buffer The raw pixel data.
+ * @param [in] bufferSize The size of the buffer in bytes
+ * @param [in] width Buffer width in pixels
+ * @param [in] height Buffer height in pixels
+ * @param [in] pixelFormat The pixel format
+ * @param [in] releaseFunction The function used to release the memory.
+ */
+ static PixelBufferPtr New( unsigned char* buffer,
+ unsigned int bufferSize,
+ unsigned int width,
+ unsigned int height,
+ Pixel::Format pixelFormat );
+
+ /**
+ * Convert a pixelBuffer object into a PixelData object.
+ * The new object takes ownership of the buffer data, and the
+ * mBuffer pointer is reset to NULL.
+ * @param[in] pixelBuffer The buffer to convert
+ * @return the pixelData
+ */
+ static Dali::PixelData Convert( PixelBuffer& pixelBuffer );
+
+ /**
+ * @brief Constructor.
+ *
+ * @param [in] buffer The raw pixel data.
+ * @param [in] bufferSize The size of the buffer in bytes
+ * @param [in] width Buffer width in pixels
+ * @param [in] height Buffer height in pixels
+ * @param [in] pixelFormat The pixel format
+ */
+ PixelBuffer( unsigned char* buffer,
+ unsigned int bufferSize,
+ unsigned int width,
+ unsigned int height,
+ Pixel::Format pixelFormat );
+
+protected:
+
+ /**
+ * @brief Destructor.
+ *
+ * Release the pixel buffer if exists.
+ */
+ ~PixelBuffer();
+
+public:
+
+ /**
+ * Get the width of the buffer in pixels.
+ * @return The width of the buffer in pixels
+ */
+ unsigned int GetWidth() const;
+
+ /**
+ * Get the height of the buffer in pixels
+ * @return The height of the buffer in pixels
+ */
+ unsigned int GetHeight() const;
+
+ /**
+ * Get the pixel format
+ * @return The pixel format
+ */
+ Pixel::Format GetPixelFormat() const;
+
+ /**
+ * Get the pixel buffer if it's present.
+ * @return The buffer if exists, or NULL if there is no pixel buffer.
+ */
+ unsigned char* GetBuffer() const;
+
+ /**
+ * Get the size of the buffer in bytes
+ * @return The size of the buffer
+ */
+ unsigned int GetBufferSize() const;
+
+ /**
+ * Copy the buffer into a new PixelData
+ */
+ Dali::PixelData CreatePixelData() const;
+
+ /**
+ * Apply the mask to the current buffer. This method may update the
+ * internal object - e.g. the new buffer may have a different pixel
+ * format - as an alpha channel may be added.
+ * @param[in] mask The mask to apply to this pixel buffer
+ */
+ void ApplyMask( const PixelBuffer& mask );
+
+private:
+ /*
+ * Undefined copy constructor.
+ */
+ PixelBuffer(const PixelBuffer& other);
+
+ /*
+ * Undefined assignment operator.
+ */
+ PixelBuffer& operator= (const PixelBuffer& other);
+
+ /**
+ * Release the buffer
+ */
+ void ReleaseBuffer();
+
+private:
+
+ unsigned char* mBuffer; ///< The raw pixel data
+ unsigned int mBufferSize; ///< Buffer sized in bytes
+ unsigned int mWidth; ///< Buffer width in pixels
+ unsigned int mHeight; ///< Buffer height in pixels
+ Pixel::Format mPixelFormat; ///< Pixel format
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+/**
+ * Helper methods for public API
+ */
+inline Internal::Adaptor::PixelBuffer& GetImplementation( Devel::PixelBuffer& handle )
+{
+ DALI_ASSERT_ALWAYS( handle && "handle is empty" );
+
+ BaseObject& object = handle.GetBaseObject();
+
+ return static_cast<Internal::Adaptor::PixelBuffer&>( object );
+}
+
+inline const Internal::Adaptor::PixelBuffer& GetImplementation( const Devel::PixelBuffer& handle )
+{
+ DALI_ASSERT_ALWAYS( handle && "handle is empty" );
+
+ const BaseObject& object = handle.GetBaseObject();
+
+ return static_cast<const Internal::Adaptor::PixelBuffer&>( object );
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H__
return 0;
}
+void VideoPlayer::SetDisplayArea( DisplayArea area )
+{
+ if( mPlugin != NULL )
+ {
+ mPlugin->SetDisplayArea( area );
+ }
+}
+
void VideoPlayer::SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation )
{
if( mPlugin != NULL )
return mFinishedSignal;
}
+void VideoPlayer::Forward( int millisecond )
+{
+ if( mPlugin != NULL )
+ {
+ mPlugin->Forward( millisecond );
+ }
+}
+
+void VideoPlayer::Backward( int millisecond )
+{
+ if( mPlugin != NULL )
+ {
+ mPlugin->Backward( millisecond );
+ }
+}
+
} // namespace Adaptor;
} // namespace Internal;
} // namespace Dali;
int GetPlayPosition();
/**
+ * @copydoc Dali::VideoPlayer::SetDisplayArea()
+ */
+ void SetDisplayArea( DisplayArea area );
+
+ /**
* @copydoc Dali::VideoPlayer::SetSetDisplayRotation()
*/
void SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation );
*/
void Initialize();
+ /**
+ * @brief Dali::VideoPlayer::Forward()
+ */
+ void Forward( int millisecond );
+
+ /**
+ * @brief Dali::VideoPlayer::Backward()
+ */
+ void Backward( int millisecond );
+
private:
/**
/**
* Create a new Window. This should only be called once by the Application class
- * @param[in] windowPosition The position and size of the window
+ * @param[in] positionSize The position and size of the window
* @param[in] name The window title
* @param[in] className The window class name
* @param[in] isTransparent Whether window is transparent
* @return A newly allocated Window
*/
- static Window* New(const PositionSize& posSize, const std::string& name, const std::string& className, bool isTransparent = false);
+ static Window* New(const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent = false);
/**
* Pass the adaptor back to the overlay. This allows the window to access Core's overlay.
int GetBrightness();
/**
+ * @copydoc Dali::DevelWindow::SetSize()
+ */
+ void SetSize( Dali::DevelWindow::WindowSize size );
+
+ /**
+ * @copydoc Dali::DevelWindow::GetSize()
+ */
+ Dali::DevelWindow::WindowSize GetSize();
+
+ /**
+ * @copydoc Dali::DevelWindow::SetPosition()
+ */
+ void SetPosition( Dali::DevelWindow::WindowPosition position );
+
+ /**
+ * @copydoc Dali::DevelWindow::GetPosition()
+ */
+ Dali::DevelWindow::WindowPosition GetPosition();
+
+ /**
* Called from Orientation after the Change signal has been sent
*/
void RotationDone( int orientation, int width, int height );
/**
* Second stage initialization
*/
- void Initialize(const PositionSize& posSize, const std::string& name, const std::string& className);
+ void Initialize(const PositionSize& positionSize, const std::string& name, const std::string& className);
/**
* Shows / hides the indicator bar.
bool mIsFocusAcceptable:1;
bool mVisible:1;
bool mOpaqueState:1;
+ bool mResizeEnabled:1;
IndicatorInterface* mIndicator;
Dali::Window::WindowOrientation mIndicatorOrientation;
Dali::Window::WindowOrientation mNextIndicatorOrientation;
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
*
*/
-
-// CLASS HEADER
-#include "property-buffer-wrapper.h"
-
// INTERNAL INCLUDES
-#include "property-value-wrapper.h"
+#include <adaptors/devel-api/adaptor-framework/application-devel.h>
+#include <adaptors/common/application-impl.h>
namespace Dali
{
-namespace Internal
-{
-namespace Emscripten
+
+namespace DevelApplication
{
-void SetPropertyBufferDataRaw(Dali::PropertyBuffer& self, const std::string& data, std::size_t size )
+Application New( int* argc, char **argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize )
{
- self.SetData( reinterpret_cast<void*>( const_cast<char*>(data.c_str()) ), size );
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL );
+ return Application( internal.Get() );
}
+} // namespace DevelApplication
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+} // namespace Dali
--- /dev/null
+#ifndef DALI_APPLICATION_DEVEL_H
+#define DALI_APPLICATION_DEVEL_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#ifdef DALI_ADAPTOR_COMPILATION // full path doesn't exist until adaptor is installed so we have to use relative
+#include <application.h>
+#else
+#include <dali/public-api/adaptor-framework/application.h>
+#endif
+
+namespace Dali
+{
+
+namespace DevelApplication
+{
+
+/**
+ * @brief This is the constructor for applications.
+ *
+ * @PRIVLEVEL_PUBLIC
+ * @PRIVILEGE_DISPLAY
+ * @param[in,out] argc A pointer to the number of arguments
+ * @param[in,out] argv A pointer to the argument list
+ * @param[in] stylesheet The path to user defined theme file
+ * @param[in] windowMode A member of WINDOW_MODE
+ * @param[in] positionSize A position and a size of the window
+ * @return A handle to the Application
+ * @note If the stylesheet is not specified, then the library's default stylesheet will not be overridden.
+ */
+DALI_IMPORT_API Application New( int* argc, char **argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize );
+
+} // namespace DevelApplication
+
+} // namespace Dali
+
+#endif // DALI_APPLICATION_DEVEL_H
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "bitmap-loader.h"
-
-// EXTERNAL INCLUDES
-#include <string>
-
-// INTERNAL INCLUDES
-#include <bitmap-loader-impl.h>
-
-namespace Dali
-{
-
-BitmapLoader BitmapLoader::New( const std::string& url,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection)
-{
- IntrusivePtr<Internal::BitmapLoader> internal = Internal::BitmapLoader::New(url, size, fittingMode, samplingMode, orientationCorrection);
- return BitmapLoader( internal.Get() );
-}
-
-BitmapLoader::BitmapLoader()
-{
-}
-
-BitmapLoader::BitmapLoader(Internal::BitmapLoader* internal)
-: BaseHandle( internal )
-{
-}
-
-BitmapLoader::~BitmapLoader()
-{
-}
-
-BitmapLoader::BitmapLoader( const BitmapLoader& handle )
-: BaseHandle( handle )
-{
-}
-
-BitmapLoader& BitmapLoader::operator=(const BitmapLoader& rhs)
-{
- BaseHandle::operator=(rhs);
- return *this;
-}
-
-void BitmapLoader::Load()
-{
- GetImplementation(*this).Load();
-}
-
-bool BitmapLoader::IsLoaded()
-{
- return GetImplementation(*this).IsLoaded();
-}
-
-std::string BitmapLoader::GetUrl() const
-{
- return GetImplementation(*this).GetUrl();
-}
-
-PixelData BitmapLoader::GetPixelData() const
-{
- return GetImplementation(*this).GetPixelData();
-}
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_BITMAP_LOADER_H
-#define DALI_BITMAP_LOADER_H
-
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-#include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/images/image-operations.h>
-#include <dali/public-api/images/pixel.h>
-#include <dali/public-api/images/pixel-data.h>
-#include <dali/public-api/object/base-handle.h>
-
-namespace Dali
-{
-namespace Internal
-{
-class BitmapLoader;
-}
-
-/**
- * @brief The BitmapLoader class is used to load bitmap from the URL synchronously.
- *
- * As the loading is synchronous, it will block the loop whilst executing.
- * Therefore, it should be used sparingly in the main event thread, and better to be called in the worker thread.
- * The Load() API is thread safe, it can be called from any thread without changing the state of DALI.
- */
-class DALI_IMPORT_API BitmapLoader : public BaseHandle
-{
-public:
-
- /**
- * @brief Create an initialized bitmap loader.
- *
- * By calling Load(), the synchronous loading is started immediately.
- *
- * @param [in] url The URL of the image file to load.
- * @param [in] size The width and height to fit the loaded image to.
- * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
- * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
- * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
- */
- static BitmapLoader New( const std::string& url,
- ImageDimensions size = ImageDimensions( 0, 0 ),
- FittingMode::Type fittingMode = FittingMode::DEFAULT,
- SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR,
- bool orientationCorrection = true);
-
- /**
- * @brief Create an empty handle.
- *
- * Use BitmapLoader::New() to create an initialized object.
- */
- BitmapLoader();
-
- /**
- * Destructor
- */
- ~BitmapLoader();
-
- /**
- * @brief This copy constructor is required for (smart) pointer semantics.
- *
- * @param [in] handle A reference to the copied handle
- */
- BitmapLoader(const BitmapLoader& handle);
-
- /**
- * @brief This assignment operator is required for (smart) pointer semantics.
- *
- * @param [in] rhs A reference to the copied handle
- * @return A reference to this
- */
- BitmapLoader& operator=(const BitmapLoader& rhs);
-
-public:
-
- /**
- * @brief Start the synchronous loading.
- */
- void Load();
-
- /**
- * @brief Query whether the image is loaded.
- *
- * @return true if the image is loaded, false otherwise.
- */
- bool IsLoaded();
-
- /**
- * @brief Returns the URL of the image.
- *
- * @return The URL of the image file.
- */
- std::string GetUrl() const;
-
- /**
- * @brief Get the pixel data.
- *
- * The returned pixel data is still valid after the BitmapLoader been destroyed.
- *
- * @return The pixel data.
- */
- PixelData GetPixelData() const;
-
-public: // Not intended for application developers
-
- explicit DALI_INTERNAL BitmapLoader(Internal::BitmapLoader*);
-};
-
-} // Dali
-
-#endif // DALI_BITMAP_LOADER_H
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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 "image-loaders/image-loader.h"
#include <resource-loader/network/file-download.h>
#include <platform-abstractions/portable/file-closer.h>
+#include "pixel-buffer-impl.h"
namespace Dali
{
namespace
{
+
// limit maximum image down load size to 50 MB
const size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024 ;
+
+static unsigned int gMaxTextureSize = 4096;
+
}
-PixelData LoadImageFromFile( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
+Devel::PixelBuffer LoadImageFromFile( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
{
Integration::BitmapResourceType resourceType( size, fittingMode, samplingMode, orientationCorrection );
- IntrusivePtr<Dali::RefObject> resource = TizenPlatform::ImageLoader::LoadImageSynchronously( resourceType, url );
- if( resource )
+ Internal::Platform::FileCloser fc( url.c_str(), "rb");
+ FILE * const fp = fc.GetFile();
+ if( fp != NULL )
{
- Integration::Bitmap* bitmap = static_cast<Integration::Bitmap*>( resource.Get() );
-
- // Use bitmap->GetBufferOwnership() to transfer the buffer ownership to pixelData.
- // The destroy of bitmap will not release the buffer, instead, the pixelData is responsible for releasing when its reference count falls to zero.
- return Dali::PixelData::New( bitmap->GetBufferOwnership(),
- bitmap->GetBufferSize(),
- bitmap->GetImageWidth(),
- bitmap->GetImageHeight(),
- bitmap->GetPixelFormat(),
- Dali::PixelData::FREE );
+ Integration::BitmapPtr bitmap;
+ bool success = TizenPlatform::ImageLoader::ConvertStreamToBitmap( resourceType, url, fp, bitmap );
+ if( success && bitmap )
+ {
+ // Use bitmap->GetBufferOwnership() to transfer the buffer ownership
+ // to pixelData. The destroy of bitmap will not release the buffer,
+ // instead, the pixelBuffer is responsible for releasing when its
+ // reference count falls to zero.
+ Internal::Adaptor::PixelBufferPtr pixelBufferImpl =
+ Internal::Adaptor::PixelBuffer::New( bitmap->GetBufferOwnership(),
+ bitmap->GetBufferSize(),
+ bitmap->GetImageWidth(),
+ bitmap->GetImageHeight(),
+ bitmap->GetPixelFormat() );
+
+ Dali::Devel::PixelBuffer pixelBuffer( pixelBufferImpl.Get() );
+ return pixelBuffer;
+ }
}
- return Dali::PixelData();
+ return Dali::Devel::PixelBuffer();
}
ImageDimensions GetClosestImageSize( const std::string& filename,
SamplingMode::Type samplingMode,
bool orientationCorrection )
{
- return TizenPlatform::ImageLoader::GetClosestImageSize( filename, size, fittingMode, samplingMode, orientationCorrection );
+ ImageDimensions dimension = TizenPlatform::ImageLoader::GetClosestImageSize( filename, size, fittingMode, samplingMode, orientationCorrection );
+
+ dimension.SetWidth( std::min( dimension.GetWidth(), static_cast< uint16_t >( GetMaxTextureSize() ) ) );
+ dimension.SetHeight( std::min( dimension.GetHeight(), static_cast< uint16_t >( GetMaxTextureSize() ) ) );
+
+ return dimension;
}
-PixelData DownloadImageSynchronously( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
+Devel::PixelBuffer DownloadImageSynchronously( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
{
Integration::BitmapResourceType resourceType( size, fittingMode, samplingMode, orientationCorrection );
if ( result && bitmap )
{
- return Dali::PixelData::New( bitmap->GetBufferOwnership(),
- bitmap->GetBufferSize(),
- bitmap->GetImageWidth(),
- bitmap->GetImageHeight(),
- bitmap->GetPixelFormat(),
- Dali::PixelData::FREE );
+ Internal::Adaptor::PixelBufferPtr pixelBufferImpl =
+ Internal::Adaptor::PixelBuffer::New( bitmap->GetBufferOwnership(),
+ bitmap->GetBufferSize(),
+ bitmap->GetImageWidth(),
+ bitmap->GetImageHeight(),
+ bitmap->GetPixelFormat() );
+
+ Dali::Devel::PixelBuffer pixelBuffer( pixelBufferImpl.Get() );
+ return pixelBuffer;
}
else
{
}
}
}
-
}
- return Dali::PixelData();
+ return Dali::Devel::PixelBuffer();
+}
+
+void SetMaxTextureSize( unsigned int size )
+{
+ gMaxTextureSize = size;
}
+unsigned int GetMaxTextureSize()
+{
+ return gMaxTextureSize;
+}
} // namespace Dali
#include <string>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/images/image-operations.h>
-#include <dali/public-api/images/pixel-data.h>
+
+#ifdef DALI_ADAPTOR_COMPILATION // full path doesn't exist until adaptor is installed so we have to use relative
+// @todo Make dali-adaptor code folder structure mirror the folder structure installed to dali-env
+#include <pixel-buffer.h>
+#else
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#endif
namespace Dali
{
* @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
* @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
* @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
- * @return handle to the loaded PixelData object or an empty handle in case loading failed.
+ * @return handle to the loaded PixelBuffer object or an empty handle in case loading failed.
*/
-DALI_IMPORT_API PixelData LoadImageFromFile(
+DALI_IMPORT_API Devel::PixelBuffer LoadImageFromFile(
const std::string& url,
ImageDimensions size = ImageDimensions( 0, 0 ),
FittingMode::Type fittingMode = FittingMode::DEFAULT,
* @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
* @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
*
- * @return handle to the loaded PixelData object or an empty handle in case downloading or decoding failed.
+ * @return handle to the loaded PixelBuffer object or an empty handle in case downloading or decoding failed.
*/
-DALI_IMPORT_API PixelData DownloadImageSynchronously(
+DALI_IMPORT_API Devel::PixelBuffer DownloadImageSynchronously(
const std::string& url,
ImageDimensions size = ImageDimensions( 0, 0 ),
FittingMode::Type fittingMode = FittingMode::DEFAULT,
SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR,
bool orientationCorrection = true );
+/**
+ * @brief Set the maximum texture size. Then size can be kwown by GL_MAX_TEXTURE_SIZE.
+ *
+ * @param [in] size The maximum texture size to set
+ */
+void SetMaxTextureSize( unsigned int size );
+
+/**
+ * @brief get the maximum texture size.
+ *
+ * @return The maximum texture size
+ */
+unsigned int GetMaxTextureSize();
} // Dali
--- /dev/null
+/*
+ * Copyright (c) 2017 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 "pixel-buffer.h"
+
+// EXTERNAL INLCUDES
+#include <stdlib.h>
+
+// INTERNAL INCLUDES
+#include <pixel-buffer-impl.h>
+
+namespace Dali
+{
+namespace Devel
+{
+
+PixelBuffer PixelBuffer::New( unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat )
+{
+ Internal::Adaptor::PixelBufferPtr internal =
+ Internal::Adaptor::PixelBuffer::New( width, height, pixelFormat );
+ return Devel::PixelBuffer( internal.Get() );
+}
+
+Dali::PixelData PixelBuffer::Convert( PixelBuffer& pixelBuffer )
+{
+ Dali::PixelData pixelData =
+ Internal::Adaptor::PixelBuffer::Convert( GetImplementation(pixelBuffer) );
+ pixelBuffer.Reset();
+ return pixelData;
+}
+
+Dali::PixelData PixelBuffer::CreatePixelData() const
+{
+ return GetImplementation(*this).CreatePixelData();
+}
+
+
+PixelBuffer::PixelBuffer()
+{
+}
+
+PixelBuffer::~PixelBuffer()
+{
+}
+
+PixelBuffer::PixelBuffer( Internal::Adaptor::PixelBuffer* internal )
+: BaseHandle( internal )
+{
+}
+
+PixelBuffer::PixelBuffer(const PixelBuffer& handle)
+: BaseHandle( handle )
+{
+}
+
+PixelBuffer& PixelBuffer::operator=(const PixelBuffer& rhs)
+{
+ BaseHandle::operator=(rhs);
+ return *this;
+}
+
+unsigned int PixelBuffer::GetWidth() const
+{
+ return GetImplementation(*this).GetWidth();
+}
+
+unsigned int PixelBuffer::GetHeight() const
+{
+ return GetImplementation(*this).GetHeight();
+}
+
+Pixel::Format PixelBuffer::GetPixelFormat() const
+{
+ return GetImplementation(*this).GetPixelFormat();
+}
+
+unsigned char* PixelBuffer::GetBuffer()
+{
+ return GetImplementation(*this).GetBuffer();
+}
+
+void PixelBuffer::ApplyMask( PixelBuffer mask )
+{
+ GetImplementation(*this).ApplyMask( GetImplementation( mask ) );
+}
+
+} // namespace Devel
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_PIXEL_BUFFER_H
+#define DALI_PIXEL_BUFFER_H
+
+/*
+ * Copyright (c) 2017 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/public-api/images/pixel.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+namespace Adaptor
+{
+class PixelBuffer;
+}
+}
+
+// Use namespace to separate from PixelBuffer typedef in buffer-image.h
+namespace Devel
+{
+
+/**
+ * @brief The PixelBuffer object holds a pixel buffer.
+ *
+ * The PixelBuffer keeps ownership of it's initial buffer however, the
+ * user is free to modify the pixel data, either directly, or via
+ * image operations.
+ *
+ * In order to upload the pixel data to texture memory, there are two
+ * possibilities - either convert it back to a PixelData object, which
+ * releases the PixelBuffer object, leaving the user with an empty handle
+ * (ideal for one-time indirect image manipulation), or create a new
+ * PixelData object from this object, leaving the buffer intact (ideal
+ * for continuous manipulation)
+ *
+ * @SINCE_1_2.46
+ */
+class DALI_IMPORT_API PixelBuffer : public BaseHandle
+{
+public:
+
+ /**
+ * Create a PixelBuffer with it's own data buffer.
+ */
+ static PixelBuffer New( unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat );
+
+ /**
+ * @brief Creates an empty handle.
+ * Use PixelBuffer::New() to create an initialized object.
+ *
+ * @SINCE_1_2.46
+ */
+ PixelBuffer();
+
+ /**
+ * @brief Destructor.
+ *
+ * @SINCE_1_2.46
+ */
+ ~PixelBuffer();
+
+ /**
+ * @brief This copy constructor is required for (smart) pointer semantics.
+ *
+ * @SINCE_1_2.46
+ * @param[in] handle A reference to the copied handle
+ */
+ PixelBuffer(const PixelBuffer& handle);
+
+ /**
+ * @brief This assignment operator is required for (smart) pointer semantics.
+ *
+ * @SINCE_1_2.46
+ * @param[in] rhs A reference to the copied handle
+ * @return A reference to this object
+ */
+ PixelBuffer& operator=(const PixelBuffer& rhs);
+
+ /**
+ * Convert to a pixel data and release the pixelBuffer's object.
+ * This handle is left empty.
+ *
+ * @warning Any other handles that keep a reference to this object
+ * will be left with no buffer, trying to access it will return NULL.
+ *
+ * @SINCE_1_2.46
+ * @param[in,out] pixelBuffer
+ * @return a new PixelData which takes ownership of the PixelBuffer's buffer.
+ */
+ static PixelData Convert( PixelBuffer& pixelBuffer );
+
+ /**
+ * Copy the data from this object into a new PixelData object, which could be
+ * used for uploading to a texture.
+ * @return a new PixelData object containing a copy of this pixel buffer's data.
+ */
+ Dali::PixelData CreatePixelData() const;
+
+ /**
+ * @brief Gets the pixel buffer. This is a pointer to the internal
+ * pixel buffer.
+ *
+ * @warning If there is no pixel buffer (e.g. this object has been
+ * converted to a PixelData), this method will return NULL.
+ *
+ * @SINCE_1_2.46
+ * @return The pixel buffer, or NULL.
+ */
+ unsigned char* GetBuffer();
+
+ /**
+ * @brief Gets the width of the buffer in pixels.
+ *
+ * @SINCE_1_2.46
+ * @return The width of the buffer in pixels
+ */
+ unsigned int GetWidth() const;
+
+ /**
+ * @brief Gets the height of the buffer in pixels.
+ *
+ * @SINCE_1_2.46
+ * @return The height of the buffer in pixels
+ */
+ unsigned int GetHeight() const;
+
+ /**
+ * @brief Gets the pixel format.
+ *
+ * @SINCE_1_2.46
+ * @return The pixel format
+ */
+ Pixel::Format GetPixelFormat() const;
+
+ /**
+ * Apply the mask to this pixel data, and return a new pixel data
+ * containing the masked image. If this PixelBuffer doesn't have an alpha channel,
+ * then the resultant PixelBuffer will be converted to a format that
+ * supports at least the width of the color channels and the alpha channel
+ * from the mask.
+ * @param[in] mask The mask to apply.
+ */
+ void ApplyMask( PixelBuffer mask );
+
+public:
+
+ /**
+ * @brief The constructor.
+ * @note Not intended for application developers.
+ * @SINCE_1_2.46
+ * @param[in] pointer A pointer to a newly allocated PixelBuffer
+ */
+ explicit DALI_INTERNAL PixelBuffer( Internal::Adaptor::PixelBuffer* pointer );
+};
+
+} // namespace Devel
+} // namespace Dali
+
+#endif // DALI_PIXEL_BUFFER_H
// EXTERNAL INCLUDES
#include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/math/rect.h>
namespace Dali
{
class Any;
+typedef Dali::Rect< int > DisplayArea;
/**
* @brief VideoPlayerPlugin is an abstract interface, used by dali-adaptor to access video player plugin.
virtual int GetPlayPosition() = 0;
/**
+ * @brief Sets the area of video display.
+ * @SINCE_1_2.46
+ * param[in] area The left-top position and size of the video display area
+ */
+ virtual void SetDisplayArea( DisplayArea area ) = 0;
+
+ /**
* @brief Sets video display rotation
* @SINCE_1_1.38
* @param[in] rotation The rotation of display
*/
virtual VideoPlayerSignalType& FinishedSignal() = 0;
+ /**
+ * @brief Seeks forward by the specified number of milliseconds.
+ *
+ * @SINCE_1_2.46
+ * @param[in] millisecond The position for forward playback
+ */
+ virtual void Forward( int millisecond ) = 0;
+
+ /**
+ * @brief Seeks backward by the specified number of milliseconds.
+ *
+ * @SINCE_1_2.46
+ * @param[in] millisecond The position for backward playback
+ */
+ virtual void Backward( int millisecond ) = 0;
+
};
} // namespace Dali;
return GetImplementation( *this ).GetPlayPosition();
}
+void VideoPlayer::SetDisplayArea( DisplayArea area )
+{
+ GetImplementation( *this ).SetDisplayArea( area );
+}
+
void VideoPlayer::SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation )
{
GetImplementation( *this ).SetDisplayRotation( rotation );
return GetImplementation( *this ).FinishedSignal();
}
+void VideoPlayer::Forward( int millisecond )
+{
+ GetImplementation( *this ).Forward( millisecond );
+}
+
+void VideoPlayer::Backward( int millisecond )
+{
+ GetImplementation( *this ).Backward( millisecond );
+}
+
} // namespace Dali;
int GetPlayPosition();
/**
+ * @brief Sets the area of video display.
+ * @SINCE_1_2.46
+ * param[in] area The left-top position and size of the video display area
+ */
+ void SetDisplayArea( DisplayArea area );
+
+ /**
* @brief Sets video display rotation
* @SINCE_1_1.38
* @param[in] rotation The rotation of display
*/
Dali::VideoPlayerPlugin::VideoPlayerSignalType& FinishedSignal();
+ /**
+ * @brief Seeks forward by the specified number of milliseconds.
+ *
+ * @SINCE_1_2.46
+ * @param[in] millisecond The position for forward playback
+ */
+ void Forward( int millisecond );
+
+ /**
+ * @brief Seeks backward by the specified number of milliseconds.
+ *
+ * @SINCE_1_2.46
+ * @param[in] millisecond The position for backward playback
+ */
+ void Backward( int millisecond );
+
private: // Not intended for application developers
/**
return GetImplementation( window ).ResizedSignal();
}
+void SetSize( Window window, WindowSize size )
+{
+ GetImplementation( window ).SetSize( size );
+}
+
+WindowSize GetSize( Window window )
+{
+ return GetImplementation( window ).GetSize();
+}
+
+void SetPosition( Window window, WindowPosition position )
+{
+ GetImplementation( window ).SetPosition( position );
+}
+
+WindowPosition GetPosition( Window window )
+{
+ return GetImplementation( window ).GetPosition();
+}
+
} // namespace DevelWindow
} // namespace Dali
// EXTERNAL INCLUDES
#include <string>
#include <dali/public-api/math/rect.h>
+#include <dali/public-api/math/uint-16-pair.h>
// INTERNAL INCLUDES
#ifdef DALI_ADAPTOR_COMPILATION // full path doesn't exist until adaptor is installed so we have to use relative
DIALOG ///< Used for simple dialog windows.
};
-typedef Signal< void (bool) > FocusSignalType; ///< Window focus signal type
-typedef Signal< void (int, int) > ResizedSignalType; ///< Window resized signal type
+typedef Uint16Pair WindowSize; ///< Window size type
+typedef Uint16Pair WindowPosition; ///< Window position type
+
+typedef Signal< void ( bool ) > FocusSignalType; ///< Window focus signal type
+typedef Signal< void ( WindowSize ) > ResizedSignalType; ///< Window resized signal type
/**
* @brief The user should connect to this signal to get a timing when window gains focus or loses focus.
*/
DALI_IMPORT_API ResizedSignalType& ResizedSignal( Window window );
+/**
+ * @brief Sets a size of the window.
+ *
+ * @param[in] window The window to set a size
+ * @param[in] size The new window size
+ */
+DALI_IMPORT_API void SetSize( Window window, WindowSize size );
+
+/**
+ * @brief Gets a size of the window.
+ *
+ * @param[in] window The window to get a size
+ * @return The size of the window
+ */
+DALI_IMPORT_API WindowSize GetSize( Window window );
+
+/**
+ * @brief Sets a position of the window.
+ *
+ * @param[in] window The window to set a position
+ * @param[in] position The new window position
+ */
+DALI_IMPORT_API void SetPosition( Window window, WindowPosition position );
+
+/**
+ * @brief Gets a position of the window.
+ *
+ * @param[in] window The window to get a position
+ * @return The position of the window
+ */
+DALI_IMPORT_API WindowPosition GetPosition( Window window );
+
} // namespace DevelWindow
} // namespace Dali
devel_api_src_files = \
$(adaptor_devel_api_dir)/adaptor-framework/accessibility-adaptor.cpp \
+ $(adaptor_devel_api_dir)/adaptor-framework/application-devel.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/application-extensions.cpp \
- $(adaptor_devel_api_dir)/adaptor-framework/bitmap-loader.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/bitmap-saver.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/clipboard.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/clipboard-event-notifier.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/orientation.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/performance-logger.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/physical-keyboard.cpp \
+ $(adaptor_devel_api_dir)/adaptor-framework/pixel-buffer.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/singleton-service.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/sound-player.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/style-monitor.cpp \
$(adaptor_devel_api_dir)/adaptor-framework/accessibility-adaptor.h \
$(adaptor_devel_api_dir)/adaptor-framework/accessibility-action-handler.h \
$(adaptor_devel_api_dir)/adaptor-framework/accessibility-gesture-handler.h \
+ $(adaptor_devel_api_dir)/adaptor-framework/application-devel.h \
$(adaptor_devel_api_dir)/adaptor-framework/application-extensions.h \
- $(adaptor_devel_api_dir)/adaptor-framework/bitmap-loader.h \
$(adaptor_devel_api_dir)/adaptor-framework/bitmap-saver.h \
$(adaptor_devel_api_dir)/adaptor-framework/clipboard-event-notifier.h \
$(adaptor_devel_api_dir)/adaptor-framework/clipboard.h \
$(adaptor_devel_api_dir)/adaptor-framework/lifecycle-controller.h \
$(adaptor_devel_api_dir)/adaptor-framework/orientation.h \
$(adaptor_devel_api_dir)/adaptor-framework/performance-logger.h \
+ $(adaptor_devel_api_dir)/adaptor-framework/pixel-buffer.h \
$(adaptor_devel_api_dir)/adaptor-framework/render-surface.h \
$(adaptor_devel_api_dir)/adaptor-framework/singleton-service.h \
$(adaptor_devel_api_dir)/adaptor-framework/sound-player.h \
$(adaptor_devel_api_dir)/adaptor-framework/virtual-keyboard.h \
$(adaptor_devel_api_dir)/adaptor-framework/physical-keyboard.h \
$(adaptor_devel_api_dir)/adaptor-framework/window-devel.h
-
#include <key-impl.h>
#include <iostream>
+#include <string.h>
+
using namespace std;
namespace Dali
return GrabKey( window, daliKey, TOPMOST);
}
+
bool UngrabKeyTopmost( Window window, Dali::KEY daliKey )
{
return UngrabKey( window, daliKey );
}
+
bool GrabKey( Window window, Dali::KEY daliKey, KeyGrabMode grabMode )
{
Ecore_Wl_Window_Keygrab_Mode wlGrabMode;
}
else if( grabMode == OVERRIDE_EXCLUSIVE )
{
- wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_EXCLUSIVE;
+ wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
}
else if( grabMode == EXCLUSIVE )
{
- wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
+ wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_EXCLUSIVE;
}
else
{
0, 0, 0, wlGrabMode );
}
+
bool UngrabKey( Window window, Dali::KEY daliKey )
{
return ecore_wl_window_keygrab_unset( AnyCast<Ecore_Wl_Window*>( window.GetNativeHandle() ),
0, 0 );
}
+
+bool GrabKeyList( Window window, const Dali::Vector<Dali::KEY>& daliKeyVector, const Dali::Vector<KeyGrabMode>& grabModeVector, Dali::Vector<bool>& returnVector)
+{
+ const Dali::Vector<bool>::SizeType returnCount = returnVector.Count();
+ const Dali::Vector<Dali::KEY>::SizeType keyCount = daliKeyVector.Count();
+ const Dali::Vector<KeyGrabMode>::SizeType keyGrabModeCount = grabModeVector.Count();
+
+ if( keyCount != keyGrabModeCount || keyCount != returnCount || keyCount == 0 )
+ {
+ return false;
+ }
+
+ eina_init();
+
+ Eina_List* keyList = NULL;
+ {
+ for( Dali::Vector<float>::SizeType index = 0; index < keyCount; ++index )
+ {
+ Ecore_Wl_Window_Keygrab_Info info;
+ info.key = const_cast<char*>(Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKeyVector[index] ));
+
+ switch( grabModeVector[index] )
+ {
+ case TOPMOST:
+ {
+ info.mode = ECORE_WL_WINDOW_KEYGRAB_TOPMOST;
+ break;
+ }
+ case SHARED:
+ {
+ info.mode = ECORE_WL_WINDOW_KEYGRAB_SHARED;
+ break;
+ }
+ case OVERRIDE_EXCLUSIVE:
+ {
+ info.mode = ECORE_WL_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
+ break;
+ }
+ case EXCLUSIVE:
+ {
+ info.mode = ECORE_WL_WINDOW_KEYGRAB_EXCLUSIVE;
+ break;
+ }
+ default:
+ {
+ info.mode = ECORE_WL_WINDOW_KEYGRAB_UNKNOWN;
+ break;
+ }
+ }
+
+ keyList = eina_list_append( keyList, &info );
+ }
+ }
+
+ Eina_List* grabList = ecore_wl_window_keygrab_list_set( AnyCast<Ecore_Wl_Window*>( window.GetNativeHandle() ), keyList );
+
+ returnVector.Resize( keyCount, true );
+
+ Eina_List* l = NULL;
+ Eina_List* m = NULL;
+ void *listData = NULL;
+ void *data = NULL;
+ if( grabList != NULL )
+ {
+ EINA_LIST_FOREACH( grabList, m, data )
+ {
+ Dali::Vector<float>::SizeType index = 0;
+ EINA_LIST_FOREACH( keyList, l, listData )
+ {
+ if((static_cast<Ecore_Wl_Window_Keygrab_Info*>(listData))->key == NULL)
+ {
+ DALI_LOG_ERROR("input key list has null data!");
+ break;
+ }
+
+ if( strcmp( static_cast<char*>(data), static_cast<Ecore_Wl_Window_Keygrab_Info*>(listData)->key ) == 0 )
+ {
+ returnVector[index] = false;
+ }
+ ++index;
+ }
+ }
+ }
+
+ eina_list_free( keyList );
+ eina_list_free( grabList );
+ eina_shutdown();
+
+ return true;
+}
+
+bool UngrabKeyList( Window window, const Dali::Vector<Dali::KEY>& daliKeyVector, Dali::Vector<bool>& returnVector)
+{
+ const Dali::Vector<bool>::SizeType returnCount = returnVector.Count();
+ const Dali::Vector<Dali::KEY>::SizeType keyCount = daliKeyVector.Count();
+
+ if( keyCount != returnCount ||keyCount == 0 )
+ {
+ return false;
+ }
+
+ eina_init();
+
+ Eina_List* keyList = NULL;
+ {
+ for( Dali::Vector<float>::SizeType index = 0; index < keyCount; ++index )
+ {
+ Ecore_Wl_Window_Keygrab_Info info;
+ info.key = const_cast<char*>(Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKeyVector[index] ));
+ keyList = eina_list_append( keyList, &info );
+ }
+ }
+
+ Eina_List* ungrabList = ecore_wl_window_keygrab_list_unset( AnyCast<Ecore_Wl_Window*>( window.GetNativeHandle() ), keyList );
+
+ returnVector.Resize( keyCount, true );
+
+ Eina_List* l = NULL;
+ Eina_List* m = NULL;
+ void *listData = NULL;
+ void *data = NULL;
+
+ if( ungrabList != NULL )
+ {
+ EINA_LIST_FOREACH( ungrabList, m, data )
+ {
+ Dali::Vector<float>::SizeType index = 0;
+ EINA_LIST_FOREACH( keyList, l, listData )
+ {
+ if( strcmp( static_cast<char*>(data), static_cast<Ecore_Wl_Window_Keygrab_Info*>(listData)->key ) == 0 )
+ {
+ returnVector[index] = false;
+ }
+ ++index;
+ }
+ }
+ }
+
+ eina_list_free( keyList );
+ eina_list_free( ungrabList );
+ eina_shutdown();
+
+ return true;
+}
+
} // namespace KeyGrab
} // namespace Dali
-
bool mBrightnessChangeDone;
};
-Window* Window::New(const PositionSize& posSize, const std::string& name, const std::string& className, bool isTransparent)
+Window* Window::New( const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent )
{
Window* window = new Window();
window->mIsTransparent = isTransparent;
- window->Initialize(posSize, name, className);
+ window->Initialize( positionSize, name, className );
return window;
}
mIsFocusAcceptable( true ),
mVisible( true ),
mOpaqueState( false ),
+ mResizeEnabled( false ),
mIndicator( NULL ),
mIndicatorOrientation( Dali::Window::PORTRAIT ),
mNextIndicatorOrientation( Dali::Window::PORTRAIT ),
mAuxiliaryHints.clear();
}
-void Window::Initialize(const PositionSize& windowPosition, const std::string& name, const std::string& className)
+void Window::Initialize(const PositionSize& positionSize, const std::string& name, const std::string& className)
{
// create an Wayland window by default
Any surface;
- ECore::WindowRenderSurface* windowSurface = new ECore::WindowRenderSurface( windowPosition, surface, name, mIsTransparent );
+ ECore::WindowRenderSurface* windowSurface = new ECore::WindowRenderSurface( positionSize, surface, name, mIsTransparent );
mSurface = windowSurface;
- SetClass( name, className );
- windowSurface->Map();
-
- mOrientation = Orientation::New(this);
// create event handler for Wayland window
mEventHandler = new EventHandler( this );
DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::Initialize: %s\n", hint );
}
}
+
+ if( !positionSize.IsEmpty() )
+ {
+ AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
+ mResizeEnabled = true;
+ }
+
+ SetClass( name, className );
+ windowSurface->Map();
+
+ mOrientation = Orientation::New(this);
}
void Window::DoShowIndicator( Dali::Window::WindowOrientation lastOrientation )
void Window::RotationDone( int orientation, int width, int height )
{
- PositionSize positionSize( 0, 0, width, height );
-
- mAdaptor->SurfaceSizeChanged( positionSize );
+ mAdaptor->SurfaceSizeChanged( Dali::Adaptor::SurfaceSize( width, height ) );
// Emit signal
- mResizedSignal.Emit( positionSize.width, positionSize.height );
+ mResizedSignal.Emit( Dali::DevelWindow::WindowSize( width, height ) );
Dali::Window::WindowOrientation windowOrientation;
switch( orientation )
}
ECore::WindowRenderSurface* wlSurface( dynamic_cast< ECore::WindowRenderSurface * >( mSurface ) );
- wlSurface->RequestRotation( windowOrientation, positionSize.width, positionSize.height );
+ wlSurface->RequestRotation( windowOrientation, width, height );
}
unsigned int Window::GetSupportedAuxiliaryHintCount()
return mEventHandler->mBrightness;
}
+void Window::SetSize( Dali::DevelWindow::WindowSize size )
+{
+ if( !mResizeEnabled )
+ {
+ AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
+ mResizeEnabled = true;
+ }
+
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ if( positionSize.width != size.GetWidth() || positionSize.height != size.GetHeight() )
+ {
+ positionSize.width = size.GetWidth();
+ positionSize.height = size.GetHeight();
+
+ mSurface->MoveResize( positionSize );
+
+ mAdaptor->SurfaceSizeChanged( Dali::Adaptor::SurfaceSize( positionSize.width, positionSize.height ) );
+
+ // Emit signal
+ mResizedSignal.Emit( Dali::DevelWindow::WindowSize( positionSize.width, positionSize.height ) );
+ }
+}
+
+Dali::DevelWindow::WindowSize Window::GetSize()
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ return Dali::DevelWindow::WindowSize( positionSize.width, positionSize.height );
+}
+
+void Window::SetPosition( Dali::DevelWindow::WindowPosition position )
+{
+ if( !mResizeEnabled )
+ {
+ AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
+ mResizeEnabled = true;
+ }
+
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ if( positionSize.x != position.GetX() || positionSize.y != position.GetY() )
+ {
+ positionSize.x = position.GetX();
+ positionSize.y = position.GetY();
+
+ mSurface->MoveResize( positionSize );
+ }
+}
+
+Dali::DevelWindow::WindowPosition Window::GetPosition()
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ return Dali::DevelWindow::WindowPosition( positionSize.x, positionSize.y );
+}
+
} // Adaptor
} // Internal
#include <window-render-surface.h>
// EXTERNAL INCLUDES
+#include <dlfcn.h>
#include <dali/integration-api/gl-abstraction.h>
#include <dali/integration-api/debug.h>
#include <dali/integration-api/gl-defines.h>
{
const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
+const char* WAYLAND_EGL_SO( "libwayland-egl.so" );
} // unnamed namespace
const std::string& name,
bool isTransparent)
: EcoreWlRenderSurface( positionSize, surface, name, isTransparent ),
+ mEglWinGetCapabilitiesPtr( NULL ),
+ mEglWinSetRotationPtr( NULL ),
+ mLibHandle( NULL ),
mWlWindow( NULL ),
+ mWlSurface( NULL ),
mEglWindow( NULL ),
mThreadSynchronization( NULL ),
mRotationTrigger( NULL ),
{
delete mRotationTrigger;
}
+
+ if( mLibHandle != NULL )
+ {
+ dlclose( mLibHandle );
+ }
}
Ecore_Wl_Window* WindowRenderSurface::GetDrawable()
ecore_wl_window_rotation_set( mWlWindow, angle );
- wl_egl_window_set_rotation( mEglWindow, rotation );
+ if( mEglWinSetRotationPtr )
+ {
+ mEglWinSetRotationPtr( mEglWindow, rotation );
+ }
}
void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
ecore_wl_window_alpha_set( mWlWindow, false );
}
- // create the EGL surface
- ecore_wl_window_surface_create(mWlWindow);
- mEglWindow = wl_egl_window_create(ecore_wl_window_surface_get(mWlWindow), mPosition.width, mPosition.height);
+ // create the EGL window
+ mEglWindow = wl_egl_window_create( mWlSurface, mPosition.width, mPosition.height );
EGLNativeWindowType windowType( mEglWindow );
eglImpl.CreateSurfaceWindow( windowType, mColorDepth );
// Check capability
- wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( wl_egl_window_get_capabilities( mEglWindow ) );
- if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
+ if( !mLibHandle )
+ {
+ mLibHandle = dlopen( WAYLAND_EGL_SO, RTLD_LAZY );
+
+ char* error = dlerror();
+ if( mLibHandle == NULL || error != NULL )
+ {
+ DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: dlopen error: %s\n", error );
+ return;
+ }
+
+ mEglWinGetCapabilitiesPtr = reinterpret_cast< EglWinGetCapabilitiesFunction >( dlsym( mLibHandle, "wl_egl_window_get_capabilities" ) );
+ if( !mEglWinGetCapabilitiesPtr )
+ {
+ DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: Can't load wl_egl_window_get_capabilities\n" );
+ return;
+ }
+
+ mEglWinSetRotationPtr = reinterpret_cast< EglWinSetRotationFunction >( dlsym( mLibHandle, "wl_egl_window_set_rotation" ) );
+ if( !mEglWinSetRotationPtr )
+ {
+ DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: Can't load wl_egl_window_set_rotation\n" );
+ return;
+ }
+ }
+
+ if( mEglWinGetCapabilitiesPtr )
{
- DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: capability = %d\n", capability );
- mRotationSupported = true;
+ wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( mEglWinGetCapabilitiesPtr( mEglWindow ) );
+ if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
+ {
+ DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: capability = %d\n", capability );
+ mRotationSupported = true;
+ }
}
}
ecore_wl_window_alpha_set( mWlWindow, false );
}
- mEglWindow = wl_egl_window_create(ecore_wl_window_surface_get(mWlWindow), mPosition.width, mPosition.height);
+ mEglWindow = wl_egl_window_create( mWlSurface, mPosition.width, mPosition.height );
Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
EGLNativeWindowType windowType( mEglWindow );
if(needToMove)
{
- ecore_wl_window_move(mWlWindow, positionSize.x, positionSize.y);
- mPosition = positionSize;
+ ecore_wl_window_position_set( mWlWindow, positionSize.x, positionSize.y );
}
if (needToResize)
{
- ecore_wl_window_resize(mWlWindow, positionSize.width, positionSize.height, 0);
- mPosition = positionSize;
+ ecore_wl_window_update_size( mWlWindow, positionSize.width, positionSize.height );
}
+ mPosition = positionSize;
+
+ wl_egl_window_resize( mEglWindow, mPosition.width, mPosition.height, mPosition.x, mPosition.y );
+
+ DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPosition.x, mPosition.y, mPosition.width, mPosition.height );
}
void WindowRenderSurface::Map()
{
DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
}
+
+ mWlSurface = ecore_wl_window_surface_create( mWlWindow );
}
void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
private: // Data
- Ecore_Wl_Window* mWlWindow; ///< Wayland-Window
+ typedef int (*EglWinGetCapabilitiesFunction)( wl_egl_window* eglWindow );
+ typedef int (*EglWinSetRotationFunction)( wl_egl_window* eglWindow, int rotation );
+
+ EglWinGetCapabilitiesFunction mEglWinGetCapabilitiesPtr;
+ EglWinSetRotationFunction mEglWinSetRotationPtr;
+
+ void* mLibHandle; ///< Handle for the loaded library
+ Ecore_Wl_Window* mWlWindow; ///< Wayland-Window
+ wl_surface* mWlSurface;
wl_egl_window* mEglWindow;
ThreadSynchronizationInterface* mThreadSynchronization;
TriggerEventInterface* mRotationTrigger;
+++ /dev/null
-/*
-Copyright (c) 2000-2013 Samsung Electronics Co., Ltd All Rights Reserved
-
-This file is part of Dali Adaptor
-
-PROPRIETARY/CONFIDENTIAL
-
-This software is the confidential and proprietary information of
-SAMSUNG ELECTRONICS ("Confidential Information"). You shall not
-disclose such Confidential Information and shall use it only in
-accordance with the terms of the license agreement you entered
-into with SAMSUNG ELECTRONICS.
-
-SAMSUNG make no representations or warranties about the suitability
-of the software, either express or implied, including but not limited
-to the implied warranties of merchantability, fitness for a particular
-purpose, or non-infringement. SAMSUNG shall not be liable for any
-damages suffered by licensee as a result of using, modifying or
-distributing this software or its derivatives.
-*/
-
-
-// CLASS HEADER
-#include <gl/egl-implementation.h>
-
-// EXTERNAL INCLUDES
-#include <iostream>
-#include <dali/integration-api/debug.h>
-#include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-namespace
-{
-
-#if defined(DEBUG_ENABLED)
-
-void PrintConfigs(EGLDisplay d)
-{
- EGLint numConfigs;
-
- eglGetConfigs(d, NULL, 0, &numConfigs);
- EGLConfig *configs = new EGLConfig[numConfigs];
-
- eglGetConfigs(d, configs, numConfigs, &numConfigs);
-
- printf("Configurations: N=%d\n", numConfigs);
- printf(" - config id\n");
- printf(" - buffer size\n");
- printf(" - level\n");
- printf(" - double buffer\n");
- printf(" - stereo\n");
- printf(" - r, g, b\n");
- printf(" - depth\n");
- printf(" - stencil\n");
-
- printf(" bf lv d st colorbuffer dp st supported \n");
- printf(" id sz l b ro r g b a th cl surfaces \n");
- printf("----------------------------------------------\n");
- for (EGLint i = 0; i < numConfigs; i++) {
- EGLint id, size, level;
- EGLint red, green, blue, alpha;
- EGLint depth, stencil;
- EGLint surfaces;
- EGLint doubleBuf = 1, stereo = 0;
- char surfString[100] = "";
-
- eglGetConfigAttrib(d, configs[i], EGL_CONFIG_ID, &id);
- eglGetConfigAttrib(d, configs[i], EGL_BUFFER_SIZE, &size);
- eglGetConfigAttrib(d, configs[i], EGL_LEVEL, &level);
-
- eglGetConfigAttrib(d, configs[i], EGL_RED_SIZE, &red);
- eglGetConfigAttrib(d, configs[i], EGL_GREEN_SIZE, &green);
- eglGetConfigAttrib(d, configs[i], EGL_BLUE_SIZE, &blue);
- eglGetConfigAttrib(d, configs[i], EGL_ALPHA_SIZE, &alpha);
- eglGetConfigAttrib(d, configs[i], EGL_DEPTH_SIZE, &depth);
- eglGetConfigAttrib(d, configs[i], EGL_STENCIL_SIZE, &stencil);
- eglGetConfigAttrib(d, configs[i], EGL_SURFACE_TYPE, &surfaces);
-
- if (surfaces & EGL_WINDOW_BIT)
- strcat(surfString, "win,");
- if (surfaces & EGL_PBUFFER_BIT)
- strcat(surfString, "pb,");
- if (surfaces & EGL_PIXMAP_BIT)
- strcat(surfString, "pix,");
- if (strlen(surfString) > 0)
- surfString[strlen(surfString) - 1] = 0;
-
- printf("0x%02x %2d %2d %c %c %2d %2d %2d %2d %2d %2d %-12s\n",
- id, size, level,
- doubleBuf ? 'y' : '.',
- stereo ? 'y' : '.',
- red, green, blue, alpha,
- depth, stencil, surfString);
- }
-
- delete [] configs;
-}
-
-#endif
-
-} // namespace anon
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Adaptor
-{
-
-#define TEST_EGL_ERROR(lastCommand) \
-{ \
- EGLint err = eglGetError(); \
- if (err != EGL_SUCCESS) \
- { \
- printf("EGL error after %s code=%x\n", lastCommand, err); \
- DALI_LOG_ERROR("EGL error after %s code=%x\n", lastCommand,err); \
- DALI_ASSERT_ALWAYS(0 && "EGL error"); \
- } \
-}
-
-EglImplementation::EglImplementation()
- : mEglNativeDisplay(0),
- mCurrentEglNativePixmap(0),
- mEglDisplay(0),
- mEglConfig(0),
- mEglContext(0),
- mCurrentEglSurface(0),
- mGlesInitialized(false),
- mIsOwnSurface(true),
- mContextCurrent(false),
- mIsWindow(true),
- mColorDepth(COLOR_DEPTH_24)
-{
-}
-
-EglImplementation::~EglImplementation()
-{
- TerminateGles();
-}
-
-bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
-{
- if ( !mGlesInitialized )
- {
- mEglNativeDisplay = display;
-
- //@todo see if we can just EGL_DEFAULT_DISPLAY instead
- mEglDisplay = eglGetDisplay(mEglNativeDisplay);
-
- EGLint majorVersion = 0;
- EGLint minorVersion = 0;
- if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
- {
- return false;
- }
- eglBindAPI(EGL_OPENGL_ES_API);
-
-#if defined(DEBUG_ENABLED)
- PrintConfigs(mEglDisplay);
-#endif
-
- mContextAttribs.Clear();
-
-#if DALI_GLES_VERSION >= 30
-
- mContextAttribs.Reserve(5);
- mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
- mContextAttribs.PushBack( 3 );
- mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
- mContextAttribs.PushBack( 0 );
-
-#else // DALI_GLES_VERSION >= 30
-
- mContextAttribs.Reserve(3);
- mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
- mContextAttribs.PushBack( 2 );
-
-#endif // DALI_GLES_VERSION >= 30
-
- mContextAttribs.PushBack( EGL_NONE );
-
- mGlesInitialized = true;
- mIsOwnSurface = isOwnSurface;
- }
-
- return mGlesInitialized;
-}
-
-bool EglImplementation::CreateContext()
-{
- // make sure a context isn't created twice
- DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
- DALI_ASSERT_ALWAYS( mGlesInitialized );
-
- mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
-
- // if emscripten ignore this (egl spec says non gles2 implementation must return EGL_BAD_MATCH if it doesnt support gles2)
- // so just ignore error for now....
- // TEST_EGL_ERROR("eglCreateContext render thread");
- // DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
-
- return true;
-}
-
-void EglImplementation::DestroyContext()
-{
- DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
-
- eglDestroyContext( mEglDisplay, mEglContext );
- mEglContext = 0;
-}
-
-void EglImplementation::DestroySurface()
-{
- if(mIsOwnSurface && mCurrentEglSurface)
- {
- eglDestroySurface( mEglDisplay, mCurrentEglSurface );
- mCurrentEglSurface = 0;
- }
-}
-
-void EglImplementation::MakeContextCurrent()
-{
- mContextCurrent = true;
-
- if(mIsOwnSurface)
- {
- eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
- }
-
- EGLint error = eglGetError();
-
- if ( error != EGL_SUCCESS )
- {
- switch (error)
- {
- case EGL_BAD_DISPLAY:
- {
- DALI_LOG_ERROR("EGL_BAD_DISPLAY : Display is not an EGL display connection\n");
- break;
- }
- case EGL_NOT_INITIALIZED:
- {
- DALI_LOG_ERROR("EGL_NOT_INITIALIZED : Display has not been initialized\n");
- break;
- }
- case EGL_BAD_SURFACE:
- {
- DALI_LOG_ERROR("EGL_BAD_SURFACE : Draw or read is not an EGL surface\n");
- break;
- }
- case EGL_BAD_CONTEXT:
- {
- DALI_LOG_ERROR("EGL_BAD_CONTEXT : Context is not an EGL rendering context\n");
- break;
- }
- case EGL_BAD_MATCH:
- {
- DALI_LOG_ERROR("EGL_BAD_MATCH : Draw or read are not compatible with context, or if context is set to EGL_NO_CONTEXT and draw or read are not set to EGL_NO_SURFACE, or if draw or read are set to EGL_NO_SURFACE and context is not set to EGL_NO_CONTEXT\n");
- break;
- }
- case EGL_BAD_ACCESS:
- {
- DALI_LOG_ERROR("EGL_BAD_ACCESS : Context is current to some other thread\n");
- break;
- }
- case EGL_BAD_NATIVE_PIXMAP:
- {
- DALI_LOG_ERROR("EGL_BAD_NATIVE_PIXMAP : A native pixmap underlying either draw or read is no longer valid.\n");
- break;
- }
- case EGL_BAD_NATIVE_WINDOW:
- {
- DALI_LOG_ERROR("EGL_BAD_NATIVE_WINDOW : A native window underlying either draw or read is no longer valid.\n");
- break;
- }
- case EGL_BAD_CURRENT_SURFACE:
- {
- DALI_LOG_ERROR("EGL_BAD_CURRENT_SURFACE : The previous context has unflushed commands and the previous surface is no longer valid.\n");
- break;
- }
- case EGL_BAD_ALLOC:
- {
- DALI_LOG_ERROR("EGL_BAD_ALLOC : Allocation of ancillary buffers for draw or read were delayed until eglMakeCurrent is called, and there are not enough resources to allocate them\n");
- break;
- }
- case EGL_CONTEXT_LOST:
- {
- DALI_LOG_ERROR("EGL_CONTEXT_LOST : If a power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering\n");
- break;
- }
- default:
- {
- DALI_LOG_ERROR("Unknown error\n");
- break;
- }
- }
- DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
- }
-
- DALI_LOG_WARNING("- EGL Information\nVendor: %s\nVersion: %s\nClient APIs: %s\nExtensions: %s\n",
- eglQueryString(mEglDisplay, EGL_VENDOR),
- eglQueryString(mEglDisplay, EGL_VERSION),
- eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
- eglQueryString(mEglDisplay, EGL_EXTENSIONS));
-
-}
-
-void EglImplementation::MakeContextNull()
-{
- mContextCurrent = false;
- // clear the current context
- eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
-}
-
-void EglImplementation::TerminateGles()
-{
- if ( mGlesInitialized )
- {
- // in latest Mali DDK (r2p3 ~ r3p0 in April, 2012),
- // MakeContextNull should be called before eglDestroy surface
- // to prevent crash in _mali_surface_destroy_callback
- MakeContextNull();
-
- if(mIsOwnSurface && mCurrentEglSurface)
- {
- eglDestroySurface(mEglDisplay, mCurrentEglSurface);
- }
- eglDestroyContext(mEglDisplay, mEglContext);
-
- eglTerminate(mEglDisplay);
-
- mEglDisplay = NULL;
- mEglConfig = NULL;
- mEglContext = NULL;
- mCurrentEglSurface = NULL;
-
- mGlesInitialized = false;
- }
-}
-
-bool EglImplementation::IsGlesInitialized() const
-{
- return mGlesInitialized;
-}
-
-void EglImplementation::SwapBuffers()
-{
- eglSwapBuffers( mEglDisplay, mCurrentEglSurface );
-}
-
-void EglImplementation::CopyBuffers()
-{
- eglCopyBuffers( mEglDisplay, mCurrentEglSurface, mCurrentEglNativePixmap );
-}
-
-void EglImplementation::WaitGL()
-{
- eglWaitGL();
-}
-
-void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
-{
- if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
- {
- return;
- }
-
- mIsWindow = isWindowType;
-
- EGLint numConfigs;
- Vector<EGLint> configAttribs;
- configAttribs.Reserve(31);
-
- if(isWindowType)
- {
- configAttribs.PushBack( EGL_SURFACE_TYPE );
- configAttribs.PushBack( EGL_WINDOW_BIT );
- }
- else
- {
- DALI_ASSERT_ALWAYS(!"uninplemented");
- configAttribs.PushBack( EGL_SURFACE_TYPE );
- configAttribs.PushBack( EGL_PIXMAP_BIT );
- }
-
- configAttribs.PushBack( EGL_RENDERABLE_TYPE );
-
-#if DALI_GLES_VERSION >= 30
- DALI_ASSERT_ALWAYS(!"uninplemented");
-
-#ifdef _ARCH_ARM_
- configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
-#else
- // There is a bug in the desktop emulator
- // Requesting for ES3 causes eglCreateContext even though it allows to ask
- // for a configuration that supports GLES 3.0
- configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
-#endif // _ARCH_ARM_
-
-#else // DALI_GLES_VERSION >= 30
-
- configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
-
-#endif //DALI_GLES_VERSION >= 30
-
- configAttribs.PushBack( EGL_RED_SIZE );
- configAttribs.PushBack( 8 );
- configAttribs.PushBack( EGL_GREEN_SIZE );
- configAttribs.PushBack( 8 );
- configAttribs.PushBack( EGL_BLUE_SIZE );
- configAttribs.PushBack( 8 );
-
- //
- // Setting the alpha crashed .... need SDL_SetVideo(...) with alpha somehow??
- //
-
- configAttribs.PushBack( EGL_ALPHA_SIZE );
- configAttribs.PushBack( 8 );
- configAttribs.PushBack( EGL_DEPTH_SIZE );
- configAttribs.PushBack( 24 );
-
- configAttribs.PushBack( EGL_NONE );
-
- if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
- {
- EGLint error = eglGetError();
- switch (error)
- {
- case EGL_BAD_DISPLAY:
- {
- DALI_LOG_ERROR("Display is not an EGL display connection\n");
- break;
- }
- case EGL_BAD_ATTRIBUTE:
- {
- DALI_LOG_ERROR("The parameter confirAttribs contains an invalid frame buffer configuration attribute or an attribute value that is unrecognized or out of range\n");
- break;
- }
- case EGL_NOT_INITIALIZED:
- {
- DALI_LOG_ERROR("Display has not been initialized\n");
- break;
- }
- case EGL_BAD_PARAMETER:
- {
- DALI_LOG_ERROR("The parameter numConfig is NULL\n");
- break;
- }
- default:
- {
- DALI_LOG_ERROR("Unknown error\n");
- }
- }
- DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
- }
-
- if ( numConfigs != 1 )
- {
- DALI_LOG_ERROR("No configurations found.\n");
- TEST_EGL_ERROR("eglChooseConfig");
- }
-}
-
-
-void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
-{
- DALI_ASSERT_ALWAYS( ( mCurrentEglSurface == 0 ) && "EGL surface already exists" );
-
- mColorDepth = depth;
- mIsWindow = true;
-
- // egl choose config
- static_cast<void>(window);
- EGLNativeWindowType dummyWindow = NULL;
-
- mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, dummyWindow, NULL );
-
-
- TEST_EGL_ERROR("eglCreateWindowSurface");
-
- DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
-}
-
-
-EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
-{
- DALI_ASSERT_ALWAYS( mCurrentEglSurface == 0 && "Cannot create more than one instance of surface pixmap" );
-
- mCurrentEglNativePixmap = pixmap;
- mColorDepth = depth;
- mIsWindow = false;
-
- // egl choose config
- ChooseConfig(mIsWindow, mColorDepth);
-
- mCurrentEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL );
- TEST_EGL_ERROR("eglCreatePixmapSurface");
-
- DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create pixmap surface failed" );
-
- return mCurrentEglSurface;
-}
-
-bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window )
-{
- DALI_ASSERT_ALWAYS(!"Unimplemented");
-
- bool contextLost = false;
-
- // the surface is bound to the context, so set the context to null
- MakeContextNull();
-
- // destroy the surface
- DestroySurface();
-
- // create the EGL surface
- CreateSurfaceWindow( window, mColorDepth );
-
- // set the context to be current with the new surface
- MakeContextCurrent();
-
- return contextLost;
-}
-
-bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface )
-{
- bool contextLost = false;
-
- // the surface is bound to the context, so set the context to null
- MakeContextNull();
-
- // destroy the surface
- DestroySurface();
-
- // create the EGL surface
- eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );
-
- // set the context to be current with the new surface
- MakeContextCurrent();
-
- return contextLost;
-}
-
-EGLDisplay EglImplementation::GetDisplay() const
-{
- return mEglDisplay;
-}
-
-EGLDisplay EglImplementation::GetContext() const
-{
- return mEglContext;
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
+++ /dev/null
-
-#include "sdl-application.h"
-#include <cassert>
-
-#include <dali/public-api/dali-core.h>
-
-#include <SDL/SDL.h>
-
-// main loop function called by emscripten/browser
-extern void emscripten_set_main_loop(void (*func)(), int fps, int simulate_infinite_loop);
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-extern void RenderFinished();
-};
-};
-};
-
-Dali::SdlApplication *app = NULL;
-
-void EmscriptenMouseEvent(double x, double y, int downUpMotion)
-{
- DALI_ASSERT_ALWAYS(app);
-
- if(app)
- {
- app->SendTouchEvent(x,y, downUpMotion);
- }
-}
-
-void ProcessEvents()
-{
- SDL_PumpEvents();
-
- //
- // This wasnt working prior to emscripten v1.25
- //
- // But it only gives event inside the gl window.
- // When dragging (for rotation etc) we want the drag/rotate to continue outside the window
- //
- // So we'll disable this handling for now
- //
- SDL_Event event;
- while (SDL_PollEvent(&event))
- {
- } // Poll(event)
-
-} // ProcessEvents()
-
-
-void EmscriptenUpdateOnce()
-{
- DALI_ASSERT_ALWAYS(app);
- app->DoUpdate();
-};
-
-void EmscriptenRenderOnce()
-{
- DALI_ASSERT_ALWAYS(app);
-
- static int w = 0;
- static int h = 0;
-
- // 'Module' here should be 'dali' with emcc switch -s EXPORT_NAME="dali"
- // but on upgrading to emscripten 1.34.2 it's broken.
- int _x = EM_ASM_INT_V({ return Module.canvas.width; });
- int _y = EM_ASM_INT_V({ return Module.canvas.height; });
-
- bool resize = false;
- if( _x != w )
- {
- w = _x;
- resize = true;
- }
- if( _y != h )
- {
- h = _y;
- resize = true;
- }
- if( resize )
- {
- app->SetSurfaceWidth(w, h);
- }
-
- ProcessEvents();
-
- EmscriptenUpdateOnce();
-
- app->DoRender();
-
- Dali::Internal::Emscripten::RenderFinished();
-}
-
-int main(int argc, char *argv[])
-{
- using namespace Dali;
-
- // need to reference everything as emscripten/llvm will cut it all out so put a Actor here
- Dali::Actor actor;
-
- app = new SdlApplication( 0, 0, SdlApplication::DEFAULT_HORIZONTAL_DPI, SdlApplication::DEFAULT_VERTICAL_DPI );
-
- emscripten_set_main_loop(EmscriptenRenderOnce, 0, 1);
-
- return 1;
-}
+++ /dev/null
-// EXTERNAL INCLUDES
-#include "sdl-application.h"
-
-#include <SDL.h>
-#include <SDL_image.h>
-#include <X11/Xlib.h>
-#include <EGL/egl.h>
-#include <SDL_syswm.h>
-#include <stdio.h>
-#include <sys/select.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <stropts.h>
-#include <unistd.h>
-
-#include <dali/public-api/dali-core.h>
-#include <dali/integration-api/events/touch-event-integ.h>
-
-// INTERNAL INCLUDES
-#include "integration-api/egl-interface.h"
-#include "base/separate-update-render/frame-time.h"
-#include <gl/egl-implementation.h>
-
-#include "platform-abstractions/emscripten/emscripten-callbacks.h"
-
-// emscripten are using SDL version 1.3 that isnt available for download
-// but version 2.0 is close to version 1.3 but version 1.2 support removed.
-// This is one way it isnt.
-#if SDL_MAJOR_VERSION == 2
-# define VIDEO_FLAGS SDL_WINDOW_OPENGL
-#else
-# define VIDEO_FLAGS SDL_OPENGL
-#endif
-
-namespace
-{
-
-void LogFunction(Dali::Integration::Log::DebugPriority priority, std::string& message)
-{
- printf("%s", message.c_str());
- EM_ASM( console.log( message.c_str() ) );
-}
-
-}
-
-namespace Dali
-{
-
-typedef ::Pixmap XPixmap;
-typedef ::Window XWindow;
-typedef ::Display XDisplay;
-typedef ::Screen XScreen;
-
-const unsigned int SdlApplication::DEFAULT_SURFACE_WIDTH = 600;
-const unsigned int SdlApplication::DEFAULT_SURFACE_HEIGHT= 480;
-
-
-SdlApplication::SdlApplication( size_t surfaceWidth,
- size_t surfaceHeight,
- float horizontalDpi,
- float verticalDpi )
- : mCore( NULL ),
- mSurfaceWidth( surfaceWidth ),
- mSurfaceHeight( surfaceHeight ),
- mFrame( 0u ),
- mSeconds(0),
- mMicroSeconds(0)
-{
-
- EGLNativeDisplayType display = (EGLNativeDisplayType)XOpenDisplay(NULL);
- bool isOwnSurface = true;
- mEglImplementation.InitializeGles( display, isOwnSurface );
-
- SdlCreateWindow(surfaceWidth, surfaceHeight, "Dali");
-
- bool isWindowType = true;
- Dali::ColorDepth depth = Dali::COLOR_DEPTH_32;
- mEglImplementation.ChooseConfig( isWindowType, depth );
-
- EGLNativeWindowType window = NULL;
-
- mEglImplementation.CreateSurfaceWindow( window, depth );
-
- mEglImplementation.CreateContext();
-
- mEglImplementation.MakeContextCurrent();
-
- //
- // SDL/EGL setup, now create core
- //
- mCore = Dali::Integration::Core::New(
- mRenderController,
- mPlatformAbstraction,
- mGlAbstraction,
- mGlSyncAbstraction,
- mGestureManager,
- ResourcePolicy::DataRetention::DALI_RETAINS_ALL_DATA);
-
- mCore->ContextCreated();
- mCore->SurfaceResized( mSurfaceWidth, mSurfaceHeight );
- mCore->SetDpi( horizontalDpi, verticalDpi );
-
- Dali::Integration::Log::InstallLogFunction( LogFunction );
-
- mCore->SceneCreated();
-}
-
-SdlApplication::~SdlApplication()
-{
- Dali::Integration::Log::UninstallLogFunction();
- delete mCore;
- SDL_Quit();
-}
-
-void SdlApplication::SdlCreateWindow(size_t surfaceWidth,
- size_t surfaceHeight,
- const std::string &title)
-{
- if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
- {
- DALI_LOG_WARNING("SDL_Init Err: %s\n", SDL_GetError() );
- DALI_ASSERT_ALWAYS(!"Couldn't initialize SDL");
- }
-
- // load support for the JPG and PNG image formats
- int flags = IMG_INIT_JPG | IMG_INIT_PNG;
- int initted = IMG_Init(flags);
- if( (initted & flags) != flags)
- {
- DALI_LOG_WARNING("IMG_Init Err:%s\n", IMG_GetError());
- DALI_ASSERT_ALWAYS("!IMG_Init: Failed to init required jpg and png support!\n");
- }
-
- float gamma = 0.0;
- int bpp = 0; // 0 means current display bpp
-
- Uint32 video_flags = VIDEO_FLAGS;
-
- SDL_Surface *surface = SDL_SetVideoMode( static_cast<int>(surfaceWidth),
- static_cast<int>(surfaceHeight),
- bpp,
- video_flags );
-
- if ( surface == NULL )
- {
- DALI_LOG_WARNING("Couldn't set GL mode: %s\n", SDL_GetError());
- DALI_ASSERT_ALWAYS("Couldn't set GL mode");
- SDL_Quit();
- exit(1);
- }
-
- /* Set the window manager title bar */
- SDL_WM_SetCaption( title.c_str(), "daliweb" );
-
- /* Set the gamma for the window */
- if ( gamma != 0.0 )
- {
- SDL_SetGamma(gamma, gamma, gamma);
- }
-
-}
-
-void SdlApplication::DoUpdate( void )
-{
- // pump events
- mCore->ProcessEvents();
-
- // Update Time values
- static Internal::Adaptor::FrameTime frameTime;
- static bool init = false;
- if( !init )
- {
- frameTime.SetMinimumFrameTimeInterval( 16667 );
- init = true;
- }
-
- static unsigned int frameNo = 0;
- frameNo++;
- frameTime.SetSyncTime(frameNo);
-
- float lastFrameDelta( 0.0f );
- unsigned int lastSyncTime( 0 );
- unsigned int nextSyncTime( 0 );
- frameTime.PredictNextSyncTime( lastFrameDelta, lastSyncTime, nextSyncTime );
-
- Integration::UpdateStatus status;
-
- mCore->Update( lastFrameDelta, lastSyncTime, nextSyncTime, status );
-
- Dali::Internal::Emscripten::stats.lastFrameDeltaSeconds = lastFrameDelta;
- Dali::Internal::Emscripten::stats.lastSyncTimeMilliseconds = lastSyncTime;
- Dali::Internal::Emscripten::stats.nextSyncTimeMilliseconds = nextSyncTime;
-
- Dali::Internal::Emscripten::stats.keepUpdating = status.keepUpdating;
- Dali::Internal::Emscripten::stats.needsNotification = status.needsNotification;
- Dali::Internal::Emscripten::stats.secondsFromLastFrame = status.secondsFromLastFrame;
-
-}
-
-
-void SdlApplication::DoRender()
-{
- // render
- mCore->Render( mRenderStatus );
-
- mFrame++;
-
- Dali::Internal::Emscripten::stats.frameCount = mFrame;
-
- mEglImplementation.SwapBuffers();
-
-}
-
-void SdlApplication::SendTouchEvent(double x, double y, int mouseState)
-{
- PointState::Type state = PointState::UP;
- if( 0 == mouseState )
- {
- state = PointState::DOWN;
- }
- else if( 1 == mouseState )
- {
- state = PointState::UP;
- }
- else if( 2 == mouseState )
- {
- state = PointState::MOTION;
- }
-
- Dali::Integration::TouchEvent e;
- Dali::Integration::Point point;
- point.SetState( state );
- point.SetScreenPosition( Vector2( static_cast<float>(x), static_cast<float>(y) ) );
- e.AddPoint( point );
-
- mCore->QueueEvent(e);
-}
-
-void SdlApplication::SetSurfaceWidth( unsigned int width, unsigned height )
-{
- mSurfaceWidth = width;
- mSurfaceHeight = height;
-
- mCore->SurfaceResized( mSurfaceWidth, mSurfaceHeight );
-}
-
-}
+++ /dev/null
-#ifndef __DALI_SDL_APPLICATION_H__
-#define __DALI_SDL_APPLICATION_H__
-
-/*
-Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
-
-This file is part of Dali
-
-PROPRIETARY/CONFIDENTIAL
-
-This software is the confidential and proprietary information of
-SAMSUNG ELECTRONICS ("Confidential Information"). You shall not
-disclose such Confidential Information and shall use it only in
-accordance with the terms of the license agreement you entered
-into with SAMSUNG ELECTRONICS.
-
-SAMSUNG make no representations or warranties about the suitability
-of the software, either express or implied, including but not limited
-to the implied warranties of merchantability, fitness for a particular
-purpose, or non-infringement. SAMSUNG shall not be liable for any
-damages suffered by licensee as a result of using, modifying or
-distributing this software or its derivatives.
-*/
-
-// INTERNAL INCLUDES
-#include "platform-abstractions/emscripten/emscripten-platform-abstraction.h"
-#include "sdl-gesture-manager.h"
-#include "adaptors/common/gl/gl-implementation.h"
-#include "sdl-gl-sync-abstraction.h"
-#include "sdl-render-controller.h"
-#include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/signals/connection-tracker.h>
-#include <dali/integration-api/core.h>
-#include <gl/egl-implementation.h>
-
-namespace Dali
-{
-
-/**
- *
- * An SdlApplication object for Emscripten main()
- *
- * This provides libSDL calls for creating the application surface and running
- * the update and rendering.
- * The libSDL calls are stubbed by Emscripten into browser canvas construction
- * calls. The update and rendering are exposed as we are in a single threaded
- * environment and the browser needs to control the main loop.
- * Emscripten provides emscripten_set_main_loop() for the 'loop' function which
- * should render one frame and return
- *
- */
-class DALI_IMPORT_API SdlApplication : public ConnectionTracker
-{
-public:
-
- // Default values derived from H2 device.
- static const unsigned int DEFAULT_SURFACE_WIDTH;
- static const unsigned int DEFAULT_SURFACE_HEIGHT;
-
-#ifdef _CPP11
- static constexpr float DEFAULT_HORIZONTAL_DPI = 220.0f;
- static constexpr float DEFAULT_VERTICAL_DPI = 217.0f;
-#else
- static const float DEFAULT_HORIZONTAL_DPI = 220.0f;
- static const float DEFAULT_VERTICAL_DPI = 217.0f;
-#endif
-
- static const unsigned int DEFAULT_RENDER_INTERVAL = 1;
-
- /**
- * Constructor
- *
- * @param[in] surfaceWidth Initial width of the browser canvas
- * @param[in] surfaceHeight Initial height of the browser canvas
- * @param[in] horizontalDpi Horizontal Dpi
- * @param[in] verticalDpi Vertical Dpi
- */
- SdlApplication( size_t surfaceWidth = DEFAULT_SURFACE_WIDTH,
- size_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
- float horizontalDpi = DEFAULT_HORIZONTAL_DPI,
- float verticalDpi = DEFAULT_VERTICAL_DPI );
-
- /**
- * Destructor
- */
- virtual ~SdlApplication();
-
- /**
- * Run the update once.
- * The browser is a single threaded environment and this is called on a browser callback.
- */
- void DoUpdate();
-
- /**
- * Render once. The browser is a single threaded environment.
- * The browser is a single threaded environment and this is called on a browser callback.
- */
- void DoRender();
-
- /**
- * Send Touch event into Dali event loop.
- * The allows the browser to supply touch events.
- */
- void SendTouchEvent(double x, double y, int downUpMotion);
-
- /**
- * Set surface width.
- * The allows the browser to tell Dali that the rendering canvas has changed size.
- *
- * @param[in] width The surface/canvas width
- * @param[in] height The surface/canvas height
- */
- void SetSurfaceWidth( unsigned int width, unsigned height );
-
-protected:
- EmscriptenPlatformAbstraction mPlatformAbstraction;
- SdlGlSyncAbstraction mGlSyncAbstraction;
- SdlRenderController mRenderController;
- Internal::Adaptor::GlImplementation mGlAbstraction;
- SdlGestureManager mGestureManager;
-
- Integration::UpdateStatus mStatus;
- Integration::RenderStatus mRenderStatus;
-
- Integration::Core* mCore;
- Internal::Adaptor::EglImplementation mEglImplementation;
-
- unsigned int mSurfaceWidth;
- unsigned int mSurfaceHeight;
- unsigned int mFrame;
-
- unsigned int mSeconds;
- unsigned int mMicroSeconds;
-
- void SdlCreateWindow(size_t surfaceWidth,
- size_t surfaceHeight,
- const std::string &title);
-
-};
-
-} // Dali
-
-#endif // header
+++ /dev/null
-#ifndef __DALI_SDL_GESTURE_MANAGER_H__
-#define __DALI_SDL_GESTURE_MANAGER_H__
-
-/*
-Copyright (c) 2000-2012 Samsung Electronics Co., Ltd All Rights Reserved
-
-This file is part of Dali
-
-PROPRIETARY/CONFIDENTIAL
-
-This software is the confidential and proprietary information of
-SAMSUNG ELECTRONICS ("Confidential Information"). You shall not
-disclose such Confidential Information and shall use it only in
-accordance with the terms of the license agreement you entered
-into with SAMSUNG ELECTRONICS.
-
-SAMSUNG make no representations or warranties about the suitability
-of the software, either express or implied, including but not limited
-to the implied warranties of merchantability, fitness for a particular
-purpose, or non-infringement. SAMSUNG shall not be liable for any
-damages suffered by licensee as a result of using, modifying or
-distributing this software or its derivatives.
-*/
-
-// INTERNAL INCLUDES
-#include <dali/integration-api/gesture-manager.h>
-#include <dali/public-api/common/dali-common.h>
-
-namespace Dali
-{
-
-/**
- * Concrete implementation of the gesture manager class.
- *
- * A stubb class to give to core in the Emscripten/browser environment
- */
-class DALI_IMPORT_API SdlGestureManager : public Dali::Integration::GestureManager
-{
-
-public:
-
- /**
- * Constructor
- */
- SdlGestureManager()
- {
- Initialize();
- }
-
- /**
- * Destructor
- */
- virtual ~SdlGestureManager()
- {
- }
-
- /**
- * @copydoc Dali::Integration::GestureManager::Register(Gesture::Type)
- */
- virtual void Register(const Integration::GestureRequest& request)
- {
- mFunctionsCalled.Register = true;
- }
-
- /**
- * @copydoc Dali::Integration::GestureManager::Unregister(Gesture::Type)
- */
- virtual void Unregister(const Integration::GestureRequest& request)
- {
- mFunctionsCalled.Unregister = true;
- }
-
- /**
- * @copydoc Dali::Integration::GestureManager::Update(Gesture::Type)
- */
- virtual void Update(const Integration::GestureRequest& request)
- {
- mFunctionsCalled.Update = true;
- }
-
-public: // TEST FUNCTIONS
-
- // Enumeration of Gesture Manager methods
- enum SdlFuncEnum
- {
- RegisterType,
- UnregisterType,
- UpdateType,
- };
-
- /** Call this every test */
- void Initialize()
- {
- mFunctionsCalled.Reset();
- }
-
- bool WasCalled(SdlFuncEnum func)
- {
- switch(func)
- {
- case RegisterType: return mFunctionsCalled.Register;
- case UnregisterType: return mFunctionsCalled.Unregister;
- case UpdateType: return mFunctionsCalled.Update;
- }
- return false;
- }
-
- void ResetCallStatistics(SdlFuncEnum func)
- {
- switch(func)
- {
- case RegisterType: mFunctionsCalled.Register = false; break;
- case UnregisterType: mFunctionsCalled.Unregister = false; break;
- case UpdateType: mFunctionsCalled.Update = false; break;
- }
- }
-
-private:
-
- struct SdlFunctions
- {
- SdlFunctions()
- : Register(false),
- Unregister(false),
- Update(false)
- {
- }
-
- void Reset()
- {
- Register = false;
- Unregister = false;
- Update = false;
- }
-
- bool Register;
- bool Unregister;
- bool Update;
- };
-
- SdlFunctions mFunctionsCalled;
-};
-
-} // Dali
-
-#endif // __DALI_SDL_GESTURE_MANAGER_H__
+++ /dev/null
-#include "sdl-gl-sync-abstraction.h"
-
-using namespace Dali;
-
-
-class SdlSyncObject : public Integration::GlSyncAbstraction::SyncObject
-{
-public:
- virtual bool IsSynced() { return true; }
-};
-
-
-SdlGlSyncAbstraction::~SdlGlSyncAbstraction()
-{
-}
-
-bool SdlGlSyncAbstraction::SyncObject::IsSynced()
-{
- return true;
-}
-
-Integration::GlSyncAbstraction::SyncObject* SdlGlSyncAbstraction::CreateSyncObject()
-{
- return new SdlSyncObject();
-}
-
-
-void SdlGlSyncAbstraction::DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject)
-{
- delete static_cast<SdlSyncObject*>( syncObject );
-}
-
+++ /dev/null
-#ifndef __DALI_INTEGRATION_SDL_GL_SYNC_ABSTRACTION_H__
-#define __DALI_INTEGRATION_SDL_GL_SYNC_ABSTRACTION_H__
-
-//
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.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://floralicense.org/license/
-//
-// 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/integration-api/gl-sync-abstraction.h>
-
-namespace Dali
-{
-
-/**
- *
- * This is a stubb GLSyncAbstraction class to pass to core for the Emscripten/browser environment
- */
-class DALI_IMPORT_API SdlGlSyncAbstraction : public Dali::Integration::GlSyncAbstraction
-{
-public:
-
- virtual ~SdlGlSyncAbstraction();
-
- /**
- * @copydoc Dali::Integration::GlSyncAbstraction::CreateSyncObject()
- */
- virtual Integration::GlSyncAbstraction::SyncObject* CreateSyncObject();
-
- /**
- * @copydoc Dali::Integration::GlSyncAbstraction::DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject)
- */
- virtual void DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject);
-};
-
-} // namespace Dali
-
-#endif // __DALI_INTEGRATION_SDL_GL_SYNC_ABSTRACTION_H__
+++ /dev/null
-#ifndef __SDL_RENDER_CONTROLLER_H__
-#define __SDL_RENDER_CONTROLLER_H__
-
-/*
-Copyright (c) 2000-2012 Samsung Electronics Co., Ltd All Rights Reserved
-
-This file is part of Dali
-
-PROPRIETARY/CONFIDENTIAL
-
-This software is the confidential and proprietary information of
-SAMSUNG ELECTRONICS ("Confidential Information"). You shall not
-disclose such Confidential Information and shall use it only in
-accordance with the terms of the license agreement you entered
-into with SAMSUNG ELECTRONICS.
-
-SAMSUNG make no representations or warranties about the suitability
-of the software, either express or implied, including but not limited
-to the implied warranties of merchantability, fitness for a particular
-purpose, or non-infringement. SAMSUNG shall not be liable for any
-damages suffered by licensee as a result of using, modifying or
-distributing this software or its derivatives.
-*/
-
-// INTERNAL INCLUDES
-#include <dali/integration-api/render-controller.h>
-
-namespace Dali
-{
-
-/**
- * This class is a stubb RenderController to pass to core in the Emscripten/browser environment.
- *
- */
-class DALI_IMPORT_API SdlRenderController : public Dali::Integration::RenderController
-{
-public:
- SdlRenderController()
- {
- Initialize();
- }
-
- ~SdlRenderController()
- {
- }
-
- /**
- * @copydoc Dali::Integration::RenderController::RequestUpdate()
- */
- virtual void RequestUpdate()
- {
- mRequestUpdateCalled = true;
- }
-
- /**
- * @copydoc Dali::Integration::RenderController::RequestProcessEventsOnIdle()
- */
- virtual void RequestProcessEventsOnIdle()
- {
- }
-
- /**
- * @copydoc Dali::Integration::RenderController::RequestNotificationEventOnIdle()
- */
- virtual void RequestNotificationEventOnIdle()
- {
- mRequestNotificationEventOnIdleCalled = true;
- }
-
- void Initialize()
- {
- mRequestUpdateCalled = false;
- mRequestNotificationEventOnIdleCalled = false;
- }
-
-private:
- bool mRequestUpdateCalled;
- bool mRequestNotificationEventOnIdleCalled;
-};
-
-} // Dali
-
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "actor-wrapper.h"
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/scripting/scripting.h>
-
-// INTERNAL INCLUDES
-#include "emscripten-utils.h"
-#include "signal-holder.h"
-
-namespace
-{
- enum ConditionType
- {
- False, ///< Result Always False
- LessThan, ///< Magnitude of type is less than float value (arg0).
- GreaterThan, ///< Magnitude of type is greater than float value (arg0).
- Inside, ///< Magnitude of type is within float values (arg0 & arg1).
- Outside, ///< Magnitude of type is outside float values (arg0 & arg1).
- Step, ///< Value of type has crossed a step amount
- VariableStep ///< Similar to step, except user can define a list of steps from reference value
- };
-
- Dali::Scripting::StringEnum ConditionTypeTable[] =
- { { "False", ConditionType::False},
- { "LessThan", ConditionType::LessThan},
- { "GreaterThan", ConditionType::GreaterThan},
- { "Inside", ConditionType::Inside},
- { "Outside", ConditionType::Outside},
- { "Step", ConditionType::Step},
- { "VariableStep", ConditionType::VariableStep}
- };
-
-const unsigned int ConditionTypeTableSize = sizeof( ConditionTypeTable ) / sizeof( ConditionTypeTable[0] );
-
-};
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-emscripten::val JavascriptValue( const Dali::Property::Value& v );
-
-/**
- * Struct to hold notification callback
- */
-struct EmscriptenNotifiy
-{
- EmscriptenNotifiy(const emscripten::val& callback )
- : mCallback(callback) {};
- emscripten::val mCallback;
-
- void operator()(void)
- {
- emscripten::val ret = mCallback();
- }
-};
-
-/**
- * Emscripten touched signal callback.
- *
- * Provides more contextual state information to the browser with the OnTouched signal.
- *
- */
-struct EmscriptenTouchedSignal : public BaseSignalSlot
-{
- EmscriptenTouchedSignal(const emscripten::val& callback, unsigned int id)
- : mCallback(callback), mId(id) {};
- emscripten::val mCallback;
- unsigned int mId;
-
- bool OnTouched(Dali::Actor actor, const Dali::TouchData& touch)
- {
- Dali::Property::Map map;
- Dali::Property::Array points;
-
- const int pointCount = static_cast<int>( touch.GetPointCount() );
-
- map["pointCount"] = pointCount;
- map["time"] = static_cast<int>( touch.GetTime() );
-
- for( int i = 0; i < pointCount; ++i )
- {
- Dali::Property::Map pointMap;
- Dali::Actor hitActor = touch.GetHitActor( i );
-
- pointMap["deviceId"] = touch.GetDeviceId( i );
- pointMap["hitActorId"] = static_cast<int>( hitActor ? hitActor.GetId() : -1 );
- pointMap["local"] = touch.GetLocalPosition( i );
- pointMap["screen"]= touch.GetScreenPosition( i );
-
- switch( touch.GetState( i ) )
- {
- case PointState::DOWN: { pointMap["state"] = "DOWN"; break; }
- case PointState::UP: { pointMap["state"] = "UP"; break; }
- case PointState::MOTION: { pointMap["state"] = "MOTION"; break; }
- case PointState::LEAVE: { pointMap["state"] = "LEAVE"; break; }
- case PointState::STATIONARY: { pointMap["state"] = "STATIONARY"; break; }
- case PointState::INTERRUPTED: { pointMap["state"] = "INTERRUPTED"; break; }
- };
-
- points.PushBack(pointMap);
- }
-
- map["points"] = points;
-
- Dali::Property::Value value(map);
- emscripten::val ret = mCallback( actor, JavascriptValue(value) );
- return true;
- }
-
- bool OnHovered(Dali::Actor actor, const Dali::HoverEvent& event)
- {
- Dali::Property::Map map;
- Dali::Property::Array points;
-
- map["pointCount"] = static_cast<int>(event.GetPointCount());
- map["time"] = static_cast<int>(event.time);
-
- for(TouchPointContainer::const_iterator iter = event.points.begin();
- iter != event.points.end(); ++iter) {
- const Dali::TouchPoint& pt = *iter;
- Dali::Property::Map pointMap;
- pointMap["deviceId"] = pt.deviceId;
- pointMap["hitActorId"] = static_cast<int>(pt.hitActor.GetId());
- pointMap["local"] = pt.local;
- pointMap["screen"]= pt.screen;
-
- switch(pt.state)
- {
- case TouchPoint::Down: { pointMap["state"] = "Down"; break; }
- case TouchPoint::Up: { pointMap["state"] = "Up"; break; }
- case TouchPoint::Motion: { pointMap["state"] = "Motion"; break; }
- case TouchPoint::Leave: { pointMap["state"] = "Leave"; break; }
- case TouchPoint::Stationary: { pointMap["state"] = "Stationary"; break; }
- case TouchPoint::Interrupted: { pointMap["state"] = "Interrupted"; break; }
- case TouchPoint::Last: { pointMap["state"] = "Last"; break; }
- };
-
- points.PushBack(pointMap);
- }
-
- map["points"] = points;
-
- Dali::Property::Value value(map);
- emscripten::val ret = mCallback( actor, JavascriptValue(value) );
- return true;
- }
-
-};
-
-/**
- * Struct to wrap a generic Emscripten callback.
- *
- */
-struct EmscriptenSignal
-{
- EmscriptenSignal(const emscripten::val& callback, unsigned int id)
- : mCallback(callback), mId(id) {};
- emscripten::val mCallback;
- unsigned int mId;
- bool operator()()
- {
- Dali::Actor a = Dali::Stage::GetCurrent().GetRootLayer().FindChildById(mId);
- if(a)
- {
- emscripten::val ret = mCallback( a );
- }
- else
- {
- emscripten::val ret = mCallback();
- }
- return true;
- }
-};
-
-bool ConnectSignal( Dali::Actor actor,
- SignalHolder& signalHolder,
- const std::string& signalName,
- const emscripten::val& javascriptFunction )
-{
- bool ret = false;
- if(0 == signalName.compare("touched"))
- {
- EmscriptenTouchedSignal* slot = new EmscriptenTouchedSignal(javascriptFunction, actor.GetId());
- actor.TouchSignal().Connect(slot, &EmscriptenTouchedSignal::OnTouched);
- signalHolder.add(slot);
- ret = true;
- }
- else if(0 == signalName.compare("hovered"))
- {
- EmscriptenTouchedSignal* slot = new EmscriptenTouchedSignal(javascriptFunction, actor.GetId());
- actor.HoveredSignal().Connect(slot, &EmscriptenTouchedSignal::OnHovered);
- signalHolder.add(slot);
- ret = true;
- }
- else
- {
- actor.ConnectSignal( &signalHolder, signalName, EmscriptenSignal(javascriptFunction, actor.GetId()));
- ret = true;
- }
-
- return ret;
-}
-
-unsigned int AddressOf(Dali::Actor self)
-{
- return (unsigned int)&self.GetBaseObject();
-}
-
-std::vector<float> ScreenToLocal(Dali::Actor self, float screenX, float screenY)
-{
- std::vector<float> ret;
- float localX = 0.f;
- float localY = 0.f;
- bool ok = self.ScreenToLocal(localX, localY, screenX, screenY);
- if( ok )
- {
- ret.push_back(localX);
- ret.push_back(localY);
- ret.push_back(1.0);
- }
- else
- {
- ret.push_back(0.0);
- ret.push_back(0.0);
- ret.push_back(0.0);
- }
- return ret;
-}
-
-void SetPropertyNotification( Dali::Actor self,
- SignalHolder& signalHolder,
- Dali::Property::Index index, const std::string& propertyConditionType, float arg0, float arg1,
- const emscripten::val& javascriptFunction)
-{
- unsigned int i = FindEnumIndex( propertyConditionType.c_str(), ConditionTypeTable, ConditionTypeTableSize );
-
- if( i < ConditionTypeTableSize )
- {
- ConditionType type = static_cast<ConditionType>(ConditionTypeTable[i].value);
- Dali::PropertyNotification notification;
- switch(type)
- {
- case ConditionType::False:
- {
- notification = self.AddPropertyNotification( index, Dali::LessThanCondition(arg0) );
- }
- case ConditionType::LessThan:
- {
- notification = self.AddPropertyNotification( index, Dali::LessThanCondition(arg0) );
- }
- case ConditionType::GreaterThan:
- {
- notification = self.AddPropertyNotification( index, Dali::GreaterThanCondition(arg0) );
- }
- case ConditionType::Inside:
- {
- notification = self.AddPropertyNotification( index, Dali::InsideCondition(arg0, arg1) );
- }
- case ConditionType::Outside:
- {
- notification = self.AddPropertyNotification( index, Dali::OutsideCondition(arg0, arg1) );
- }
- case ConditionType::Step:
- {
- notification = self.AddPropertyNotification( index, Dali::StepCondition(arg0, arg1) );
- }
- case ConditionType::VariableStep:
- {
- notification = self.AddPropertyNotification( index, Dali::StepCondition(arg0, arg1) );
- }
- };
-
- if(notification)
- {
- notification.NotifySignal().Connect( &signalHolder, FunctorDelegate::New(EmscriptenNotifiy(javascriptFunction)) );
- }
- else
- {
- EM_ASM( throw "Cannot set notification" );
- }
- }
-}
-
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_ACTOR_WRAPPER_H__
-#define __DALI_ACTOR_WRAPPER_H__
-
-/*
- * Copyright (c) 2015 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/dali-core.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/val.h"
-
-// INTERNAL INCLUDES
-#include "signal-holder.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Exposes a representation of the actor base object pointer for javascript debugging
- *
- * @param[in] self The dali actor
- *
- * @return the address as an int
- */
-unsigned int AddressOf(Dali::Actor self);
-
-/**
- * Provides screen to local values conveniently for javascript
- *
- * @param[in] self The dali actor
- * @param[in] screenX The screen X coordinate
- * @param[in] screenY The screen Y coordinate
- *
- * @return the local coordinates
- */
-std::vector<float> ScreenToLocal(Dali::Actor self, float screenX, float screenY);
-
-/**
- * Connect a javascript function to a dali signal.
- *
- * Handles touched and hovered specially to provide more context than Dali provides.
- *
- * @param[in] actor The dali actor
- * @param[in] signalHolder The Dali signal holder
- * @param[in] signalName The name of the signal
- * @param[in] javascriptFunction The function to call back when the signal is triggered
- *
- * @return the local coordinates
- *
- */
-bool ConnectSignal( Dali::Actor actor,
- SignalHolder& signalHolder,
- const std::string& signalName,
- const emscripten::val& javascriptFunction );
-
-/**
- * Sets a javascript function to an actor property notification
- *
- * @param[in] self The dali actor
- * @param[in] signalHolder The Dali signal holder
- * @param[in] index The property Index
- * @param[in] propertyConditionType The condition type name
- * @param[in] arg0 The property notification arg0
- * @param[in] arg1 The property notification arg1
- * @param[in] propertyConditionType The condition type name
- * @param[in] javascriptFunction The function to call back when the signal is triggered
- *
- * @return the local coordinates
-
- */
-void SetPropertyNotification( Dali::Actor self,
- SignalHolder& signalHolder,
- Dali::Property::Index index, const std::string& propertyConditionType, float arg0, float arg1,
- const emscripten::val& javascriptFunction);
-
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "animation-wrapper.h"
-
-// EXTERNAL INCLUDES
-#include "emscripten/emscripten.h"
-#include <dali/devel-api/scripting/scripting.h>
-
-// INTERNAL INCLUDES
-#include "property-value-wrapper.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-void KeyFramesAddWithAlpha(Dali::KeyFrames& keyFrames, float progress, Property::Value& value,
- const std::string& alphaFunction)
-{
- Dali::AlphaFunction func(AlphaFunction::LINEAR);
-
- if( alphaFunction == "LINEAR" )
- {
- func = Dali::AlphaFunction(AlphaFunction::LINEAR);
- }
- else if( alphaFunction == "REVERSE" )
- {
- func = Dali::AlphaFunction(AlphaFunction::REVERSE);
- }
- else if( alphaFunction == "EASE_IN_SQUARE" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_IN_SQUARE);
- }
- else if( alphaFunction == "EASE_OUT_SQUARE" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_OUT_SQUARE);
- }
- else if( alphaFunction == "EASE_IN" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_IN);
- }
- else if( alphaFunction == "EASE_OUT" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_OUT);
- }
- else if( alphaFunction == "EASE_IN_OUT" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_IN_OUT);
- }
- else if( alphaFunction == "EASE_IN_SINE" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_IN_SINE);
- }
- else if( alphaFunction == "EASE_OUT_SINE" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_OUT_SINE);
- }
- else if( alphaFunction == "EASE_IN_OUT_SINE" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_IN_OUT_SINE);
- }
- else if( alphaFunction == "BOUNCE" )
- {
- func = Dali::AlphaFunction(AlphaFunction::BOUNCE);
- }
- else if( alphaFunction == "SIN" )
- {
- func = Dali::AlphaFunction(AlphaFunction::SIN);
- }
- else if( alphaFunction == "EASE_OUT_BACK" )
- {
- func = Dali::AlphaFunction(AlphaFunction::EASE_OUT_BACK);
- }
- else
- {
- EM_ASM( console.log( "KeyFramesAddWithAlpha: Unknown alpha function" ) );
- }
-
- keyFrames.Add(progress, value, func);
-}
-
-void AnimateTo(Dali::Animation& self,
- Dali::Handle& handle,
- const std::string& property,
- const Dali::Property::Value& destinationValue,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration)
-{
- DALI_ASSERT_ALWAYS(self);
-
- Dali::Property::Index propertyIndex = handle.GetPropertyIndex(property);
-
- Dali::Property::Type propertyType = handle.GetPropertyType(propertyIndex);
-
- if( propertyType != destinationValue.GetType() )
- {
- EM_ASM( throw "animateTo property types are not the same" );
- }
- else if( propertyIndex != Dali::Property::INVALID_INDEX )
- {
- Dali::Property target( handle, propertyIndex );
- self.AnimateTo( target, destinationValue, alphaFunction, Dali::TimePeriod(delay, duration) );
- }
- else
- {
- EM_ASM( throw "unknown property" );
- }
-}
-
-void AnimateBy(Dali::Animation& self,
- Dali::Handle& handle,
- const std::string& property,
- const Dali::Property::Value& destinationValue,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration)
-{
- DALI_ASSERT_ALWAYS(self);
-
- Dali::Property::Index propertyIndex = handle.GetPropertyIndex(property);
-
- Dali::Property::Type propertyType = handle.GetPropertyType(propertyIndex);
-
- if( propertyType != destinationValue.GetType() )
- {
- EM_ASM( throw "animateTo property types are not the same" );
- }
- else if( propertyIndex != Dali::Property::INVALID_INDEX )
- {
- Dali::Property target( handle, propertyIndex );
- self.AnimateBy( target, destinationValue, alphaFunction, Dali::TimePeriod(delay,duration));
- }
- else
- {
- EM_ASM( throw "unknown property" );
- }
-}
-
-void AnimateBetween(Dali::Animation& self,
- Dali::Handle& handle,
- const std::string& property,
- Dali::KeyFrames& keyFrames,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration,
- const Dali::Animation::Interpolation& interpolation)
-{
- DALI_ASSERT_ALWAYS(self);
-
- Dali::Property::Index propertyIndex = handle.GetPropertyIndex(property);
-
- if( propertyIndex != Dali::Property::INVALID_INDEX )
- {
- Dali::Property target( handle, propertyIndex );
- self.AnimateBetween(target, keyFrames, alphaFunction, Dali::TimePeriod(delay, duration), interpolation);
- }
- else
- {
- EM_ASM( throw "unknown property" );
- }
-}
-
-void AnimatePath(Dali::Animation& self,
- Dali::Handle& target,
- const Dali::Path& path,
- const Dali::Vector3& forward,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration)
-{
- DALI_ASSERT_ALWAYS(self);
-
- if(!path)
- {
- printf("Unable to add animation, bad path object\n");
- }
- else
- {
- Dali::Actor actor = Dali::Actor::DownCast(target);
- if( !actor )
- {
- printf("Unable to add path animation, bad actor\n");
- }
- else
- {
- self.Animate( actor, path, forward, alphaFunction, Dali::TimePeriod( delay, duration ) );
- }
- }
-}
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_ANIMATION_WRAPPER_H__
-#define __DALI_ANIMATION_WRAPPER_H__
-
-/*
- * Copyright (c) 2015 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/dali-core.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/bind.h"
-
-// INTERNAL INCLUDES
-#include "handle-wrapper.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Keyframe animation helper functions for Emscripten.
- *
- * Allows a string alphaFunction
- *
- * @param[in] keyFrames The dali keyframes
- * @param[in] progress The keyframe progress
- * @param[in] value The property value
- * @param[in] alphaFunction The alpha function by name
- *
- */
-void KeyFramesAddWithAlpha(Dali::KeyFrames& keyFrames, float progress, Property::Value& value,
- const std::string& alphaFunction);
-
-
-/**
- * Animation helper functions for Emscripten.
- *
- * Allows string property names without function overloading which is unavailable with Javascript
- *
- * @param[in] self The animation
- * @param[in] handle The handle to animate
- * @param[in] property The property name to animate
- * @param[in] alphaFunction The alpha function
- * @param[in] delay The animation delay
- * @param[in] duration The animation duration
- *
- */
-void AnimateTo(Dali::Animation& self,
- Dali::Handle& handle,
- const std::string& property,
- const Dali::Property::Value& destinationValue,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration);
-
-/**
- * AnimateBy helper
- *
- * Allows string property names without function overloading which is unavailable with Javascript
- *
- * @param[in] self The animation
- * @param[in] handle The handle to animate
- * @param[in] property The property name to animate
- * @param[in] alphaFunction The alpha function
- * @param[in] delay The animation delay
- * @param[in] duration The animation duration
- */
-void AnimateBy(Dali::Animation& self,
- Dali::Handle& handle,
- const std::string& property,
- const Dali::Property::Value& destinationValue,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration);
-
-/**
- * AnimateBetween helper
- *
- * Allows string property names without function overloading which is unavailable with Javascript
- *
- * @param[in] self The animation
- * @param[in] handle The handle to animate
- * @param[in] property The property name to animate
- * @param[in] alphaFunction The alpha function
- * @param[in] delay The animation delay
- * @param[in] duration The animation duration
- */
-void AnimateBetween(Dali::Animation& self,
- Dali::Handle& handle,
- const std::string& property,
- Dali::KeyFrames& keyFrames,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration,
- const Dali::Animation::Interpolation& interpolation);
-
-/**
- * AnimatePath helper (see AnimateTo docs above)
- *
- * Allows string property names without function overloading which is unavailable with Javascript
- *
- * @param[in] self The animation
- * @param[in] target The handle to animate
- * @param[in] path The dali Path
- * @param[in] forward The path animation forward vector
- * @param[in] delay The animation delay
- * @param[in] duration The animation duration
- */
-void AnimatePath(Dali::Animation& self,
- Dali::Handle& target,
- const Dali::Path& path,
- const Dali::Vector3& forward,
- const Dali::AlphaFunction::BuiltinFunction& alphaFunction,
- const float delay,
- const float duration);
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-/*
- * Copyright (c) 2016 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 <sstream>
-#include <dali/public-api/rendering/geometry.h>
-#include <dali/public-api/rendering/sampler.h>
-#include <dali/public-api/rendering/shader.h>
-#include <dali/public-api/rendering/texture-set.h>
-#include <dali/public-api/rendering/renderer.h>
-#include <dali/devel-api/scripting/scripting.h>
-#include <dali/devel-api/events/hit-test-algorithm.h>
-#include <dali/devel-api/images/texture-set-image.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/bind.h"
-#include "emscripten/val.h"
-
-// INTERNAL INCLUDES
-#include "platform-abstractions/emscripten/emscripten-callbacks.h"
-#include "platform-abstractions/emscripten/emscripten-platform-abstraction.h"
-#include "sdl-application.h"
-#include "actor-wrapper.h"
-#include "animation-wrapper.h"
-#include "emscripten-utils.h"
-#include "geometry-wrapper.h"
-#include "handle-wrapper.h"
-#include "image-wrapper.h"
-#include "property-buffer-wrapper.h"
-#include "property-value-wrapper.h"
-#include "render-task-wrapper.h"
-#include "signal-holder.h"
-#include "type-info-wrapper.h"
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// The browser javascript wrapper consists of this cpp file and a counterpart
-// javascript file.
-//
-// They work in tandem to help make the interface natural and convenient
-// for a Javascript programmer.
-//
-// Unfortunately there is no finalize/destruction in javascript so any cpp
-// objects created must be explicitly deleted. Sometimes this wrapper can
-// hide the details and simple types can be immediately marshalled to and
-// from javascript values. More often objects created must have
-// object.delete() called at the correct time.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-extern void EmscriptenMouseEvent(double x, double y, int mouseIsDown);
-extern void EmscriptenUpdateOnce();
-extern void EmscriptenRenderOnce();
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-// Javascript callbacks. These are set in the Javascript wrapper source and called
-// from the c++ wrapper source
-extern emscripten::val JSGetGlyphImage;
-extern emscripten::val JSGetImage;
-extern emscripten::val JSGetImageMetaData;
-extern emscripten::val JSRenderFinished;
-
-using namespace emscripten;
-
-/**
- * Dali Vector access for Emscripten wrapping of Dali::Vector
- */
-template<typename DaliVectorType>
-struct DaliVectorAccess
-{
- static emscripten::val Get( const DaliVectorType& v, typename DaliVectorType::SizeType index )
- {
- if (index < v.Size())
- {
- return emscripten::val(v[index]);
- }
- else
- {
- return emscripten::val::undefined();
- }
- }
-
- static bool Set( DaliVectorType& v, typename DaliVectorType::SizeType index, const typename DaliVectorType::ItemType& value)
- {
- v[index] = value;
- return true;
- }
-
- static size_t Size( DaliVectorType& v)
- {
- return v.Size();
- }
-};
-
-/**
- * Registering a Dali Vector with Emscripten to wrap for JavaScript
- */
-template<typename T>
-class_<Dali::Vector<T>> register_dali_vector(const char* name)
-{
- typedef Dali::Vector<T> DaliVecType;
-
- void (DaliVecType::*PushBack)(const T&) = &DaliVecType::PushBack;
- void (DaliVecType::*Resize)(const size_t, const T&) = &DaliVecType::Resize;
- return class_<DaliVecType>(name)
- .template constructor<>()
- .function("push_back", PushBack)
- .function("resize", Resize)
- .function("size", &DaliVectorAccess<DaliVecType>::Size)
- .function("get", &DaliVectorAccess<DaliVecType>::Get)
- .function("set", &DaliVectorAccess<DaliVecType>::Set)
-;
-};
-
-
-namespace
-{
-
-std::string VersionString()
-{
- std::stringstream versionString;
- versionString << "DALi Core: " << Dali::CORE_MAJOR_VERSION << "." << Dali::CORE_MINOR_VERSION << "." << Dali::CORE_MICRO_VERSION << " (" << Dali::CORE_BUILD_DATE << ")" << std::endl;
- return versionString.str();
-}
-
-/**
- * Creates an Actor previously registered with the TypeRegistry by name
- * Actors are currently differentiated in the dali-wrapper.js and have accessor functions
- * to support 'property.name=' access in the Javascript side object
- */
-Dali::Actor CreateActor(const std::string& name)
-{
- Dali::Actor ret;
-
- Dali::TypeRegistry registry = Dali::TypeRegistry::Get();
-
- Dali::TypeInfo typeInfo = registry.GetTypeInfo( name );
-
- if(!typeInfo)
- {
- EM_ASM( throw "Invalid type name" );
- }
- else
- {
- Dali::BaseHandle handle = typeInfo.CreateInstance();
-
- if(!handle)
- {
- EM_ASM( throw "Invalid handle. Cannot downcast (not an actor)" );
- }
-
- if( Dali::Actor actor = Dali::Actor::DownCast(handle) )
- {
- ret = actor;
- }
- }
-
- return ret;
-}
-
-/**
- * Creates any Handle from the TypeRegistry by name
- */
-Dali::Handle CreateHandle(const std::string& name)
-{
- Dali::Handle ret;
-
- Dali::TypeRegistry registry = Dali::TypeRegistry::Get();
-
- Dali::TypeInfo typeInfo = registry.GetTypeInfo( name );
-
- if(!typeInfo)
- {
- EM_ASM( throw "Invalid type name" );
- }
- else
- {
- Dali::BaseHandle base = typeInfo.CreateInstance();
- if(!base)
- {
- EM_ASM( throw "Cannot create instance (not a handle)" );
- }
- Dali::Handle handle = Dali::Handle::DownCast(base);
-
- if(!handle)
- {
- EM_ASM( throw "Invalid handle. Cannot downcast" );
- }
-
- ret = handle;
- }
-
- return ret;
-}
-
-/**
- * The functor to be used in the hit-test algorithm to check whether the actor is hittable.
- */
-bool IsActorHittableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
-{
- const std::string& name = actor.GetName();
- // by convention if not visible, or with a * starting the name or if the root layer
- return actor.IsVisible() && (name.size() ? name[0] != '*' : true);
-};
-
-/*
- * Hit Test wrapper
- *
- */
-Dali::Actor HitTest(float x, float y)
-{
- Dali::HitTestAlgorithm::Results results;
- Dali::HitTestAlgorithm::HitTest( Dali::Stage::GetCurrent(), Dali::Vector2(x,y), results, IsActorHittableFunction );
- return results.actor;
-}
-
-/**
- * Creates a solid colour actor
- */
-Dali::Actor CreateSolidColorActor( const Dali::Vector4& color, bool border, const Dali::Vector4& borderColor, const unsigned int borderSize )
-{
- static const unsigned int MAX_BORDER_SIZE( 9 );
-
- Dali::Actor image;
- if( borderSize > MAX_BORDER_SIZE )
- {
- return image;
- }
-
- const unsigned int bitmapWidth = borderSize * 2 + 2;
-
- // Using a (2 + border) x (2 + border) image gives a better blend with the GL implementation
- // than a (1 + border) x (1 + border) image
- const unsigned int bitmapSize = bitmapWidth * bitmapWidth;
- const unsigned int topLeft = bitmapWidth * borderSize + borderSize;
- const unsigned int topRight = topLeft + 1;
- const unsigned int bottomLeft = bitmapWidth * (borderSize + 1) + borderSize;
- const unsigned int bottomRight = bottomLeft + 1;
-
- Dali::BufferImage imageData;
- if(color.a != 1.0 || borderColor.a != 1.0)
- {
- imageData = Dali::BufferImage::New( bitmapWidth, bitmapWidth, Dali::Pixel::RGBA8888 );
-
- // Create the image
- Dali::PixelBuffer* pixbuf = imageData.GetBuffer();
- Dali::Vector4 outerColor = color;
- if ( border )
- {
- outerColor = borderColor;
- }
-
- for( size_t i = 0; i < bitmapSize; ++i )
- {
- if( i == topLeft ||
- i == topRight ||
- i == bottomLeft ||
- i == bottomRight )
- {
- pixbuf[i*4+0] = 0xFF * color.r;
- pixbuf[i*4+1] = 0xFF * color.g;
- pixbuf[i*4+2] = 0xFF * color.b;
- pixbuf[i*4+3] = 0xFF * color.a;
- }
- else
- {
- pixbuf[i*4+0] = 0xFF * outerColor.r;
- pixbuf[i*4+1] = 0xFF * outerColor.g;
- pixbuf[i*4+2] = 0xFF * outerColor.b;
- pixbuf[i*4+3] = 0xFF * outerColor.a;
- }
- }
- }
- else
- {
- imageData = Dali::BufferImage::New( bitmapWidth, bitmapWidth, Dali::Pixel::RGB888 );
-
- // Create the image
- Dali::PixelBuffer* pixbuf = imageData.GetBuffer();
- Dali::Vector4 outerColor = color;
- if ( border )
- {
- outerColor = borderColor;
- }
-
- for( size_t i = 0; i < bitmapSize; ++i )
- {
- if( i == topLeft ||
- i == topRight ||
- i == bottomLeft ||
- i == bottomRight )
- {
- pixbuf[i*3+0] = 0xFF * color.r;
- pixbuf[i*3+1] = 0xFF * color.g;
- pixbuf[i*3+2] = 0xFF * color.b;
- }
- else
- {
- pixbuf[i*3+0] = 0xFF * outerColor.r;
- pixbuf[i*3+1] = 0xFF * outerColor.g;
- pixbuf[i*3+2] = 0xFF * outerColor.b;
- }
- }
- }
-
- imageData.Update();
- image = Dali::Actor::New();
- image.SetAnchorPoint( Dali::AnchorPoint::CENTER );
- image.SetParentOrigin( Dali::ParentOrigin::CENTER );
-
- std::string vertexShader(
- "attribute mediump vec2 aPosition;\n"
- "varying mediump vec2 vTexCoord;\n"
- "uniform mediump mat4 uMvpMatrix;\n"
- "uniform mediump vec3 uSize;\n"
- "uniform mediump vec4 sTextureRect;\n"
- "void main()\n"
- "{\n"
- " gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n"
- " vTexCoord = aPosition + vec2(0.5);\n"
- "}\n");
-
- std::string fragmentShader(
- "varying mediump vec2 vTexCoord;\n"
- "uniform sampler2D sTexture;\n"
- "uniform lowp vec4 uColor;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor = texture2D( sTexture, vTexCoord )*uColor;\n"
- "}\n");
-
- Dali::Shader shader = Dali::Shader::New( vertexShader, fragmentShader );
-
- // Create Quad geometry
- Dali::Property::Map quadVertexFormat;
- quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
- Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
- const float halfQuadSize = .5f;
- struct QuadVertex { Dali::Vector2 position; };
- QuadVertex quadVertexData[4] = {
- { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
- { Dali::Vector2(-halfQuadSize, halfQuadSize) },
- { Dali::Vector2( halfQuadSize, -halfQuadSize) },
- { Dali::Vector2( halfQuadSize, halfQuadSize) } };
- vertexData.SetData(quadVertexData, 4);
-
- Dali::Geometry quad = Dali::Geometry::New();
- quad.AddVertexBuffer( vertexData );
- quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
-
- Dali::Renderer renderer = Dali::Renderer::New( quad, shader );
- Dali::TextureSet textureSet = Dali::TextureSet::New();
- TextureSetImage( textureSet, 0u, imageData );
- renderer.SetTextures( textureSet );
-
- image.AddRenderer( renderer );
-
- return image;
-}
-
-} // anon namespace
-
-/**
- * Sets the callback to getting a glyph (from dali-wrapper.js/browser)
- */
-void SetCallbackGetGlyphImage(const emscripten::val& callback)
-{
- JSGetGlyphImage = callback;
-}
-
-/**
- * Sets the callback to get an image (from dali-wrapper.js/browser)
- */
-void SetCallbackGetImage(const emscripten::val& callback)
-{
- JSGetImage = callback;
-}
-
-/**
- * Sets the callback to get image meta data (from dali-wrapper.js/browser)
- */
-void SetCallbackGetImageMetadata(const emscripten::val& callback)
-{
- JSGetImageMetaData = callback;
-}
-
-/**
- * Sets the callback to signal render finished to dali-wrapper.js/browser
- */
-void SetCallbackRenderFinished(const emscripten::val& callback)
-{
- JSRenderFinished = callback;
-}
-
-/**
- * Generates control points for a Path
- */
-void GenerateControlPoints(Dali::Handle& handle, float curvature)
-{
- if( handle )
- {
- Dali::Path path = Dali::Path::DownCast(handle);
- if(path)
- {
- path.GenerateControlPoints(curvature);
- }
- else
- {
- EM_ASM( throw "Handle is not a path object" );
- }
- }
- else
- {
- EM_ASM( throw "Handle is empty" );
- }
-
-}
-
-/**
- * Creating property Value Objects
- * javascript can't select on type so we have renamed constructors
- *
- * Emscripten can convert some basic types and ones we've declared as value_array(s)
- * (These are given member access offsets/functions and are for simple structs etc)
- *
- * The composite types need converting.
- */
-Dali::Property::Value PropertyValueBoolean(bool v)
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueFloat(float v)
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueInteger(int v)
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueVector2( const Dali::Vector2& v )
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueVector3( const Dali::Vector3& v )
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueVector4( const Dali::Vector4& v )
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueIntRect( int a, int b, int c, int d )
-{
- return Dali::Property::Value(Dali::Rect<int>( a, b, c, d));
-}
-
-Dali::Property::Value PropertyValueMatrix( const Dali::Matrix& v )
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueMatrix3( const Dali::Matrix3& v )
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueEuler( const Dali::Vector3& v )
-{
- return Dali::Property::Value( Dali::Quaternion(
- Dali::Radian(Dali::Degree(v.x)),
- Dali::Radian(Dali::Degree(v.y)),
- Dali::Radian(Dali::Degree(v.z)) ) );
-}
-
-Dali::Property::Value PropertyValueAxisAngle( const Dali::Vector4& v )
-{
- return Dali::Quaternion( Dali::Radian(Dali::Degree(v[3])), Dali::Vector3(v) );
-}
-
-Dali::Property::Value PropertyValueString( const std::string& v )
-{
- return Dali::Property::Value(v);
-}
-
-Dali::Property::Value PropertyValueContainer( const emscripten::val& v )
-{
- Dali::Property::Value ret;
- RecursiveSetProperty( ret, v );
- return ret;
-}
-
-/**
- * Property value accessors from Dali Property Value
- */
-bool PropertyGetBoolean(const Dali::Property::Value& v)
-{
- return v.Get<bool>();
-}
-
-float PropertyGetFloat(const Dali::Property::Value& v)
-{
- return v.Get<float>();
-}
-
-int PropertyGetInteger(const Dali::Property::Value& v)
-{
- return v.Get<int>();
-}
-
-Dali::Vector2 PropertyGetVector2(const Dali::Property::Value& v)
-{
- return v.Get<Dali::Vector2>();
-}
-
-Dali::Vector3 PropertyGetVector3(const Dali::Property::Value& v)
-{
- return v.Get<Dali::Vector3>();
-}
-
-Dali::Vector4 PropertyGetVector4(const Dali::Property::Value& v)
-{
- return v.Get<Dali::Vector4>();
-}
-
-emscripten::val PropertyGetIntRect(const Dali::Property::Value& v)
-{
- return JavascriptValue(v);
-}
-
-std::string PropertyGetString(const Dali::Property::Value& v)
-{
- return v.Get<std::string>();
-}
-
-emscripten::val PropertyGetMap(const Dali::Property::Value& v)
-{
- return JavascriptValue(v);
-}
-
-emscripten::val PropertyGetArray(const Dali::Property::Value& v)
-{
- return JavascriptValue(v);
-}
-
-emscripten::val PropertyGetMatrix(const Dali::Property::Value& v)
-{
- return JavascriptValue(v);
-}
-
-emscripten::val PropertyGetMatrix3(const Dali::Property::Value& v)
-{
- return JavascriptValue(v);
-}
-
-emscripten::val PropertyGetEuler(const Dali::Property::Value& v)
-{
- return JavascriptValue(v);
-}
-
-emscripten::val PropertyGetRotation(const Dali::Property::Value& v)
-{
- return JavascriptValue(v);
-}
-
-int PropertyGetType(Dali::Property::Value& v)
-{
- return (int)v.GetType();
-}
-
-std::string PropertyGetTypeName(Dali::Property::Value& v)
-{
- return Dali::PropertyTypes::GetName(v.GetType());
-}
-
-template <typename T>
-float MatrixGetter(T &v, int n)
-{
- return *(v.AsFloat() + n);
-}
-
-template <typename T>
-void MatrixSetter(T &v, float f, int n)
-{
- *(v.AsFloat() + n) = f;
-}
-
-float MatrixGetter0(const Dali::Matrix &v) { return MatrixGetter(v, 0); }
-float MatrixGetter1(const Dali::Matrix &v) { return MatrixGetter(v, 1); }
-float MatrixGetter2(const Dali::Matrix &v) { return MatrixGetter(v, 2); }
-float MatrixGetter3(const Dali::Matrix &v) { return MatrixGetter(v, 3); }
-float MatrixGetter4(const Dali::Matrix &v) { return MatrixGetter(v, 4); }
-float MatrixGetter5(const Dali::Matrix &v) { return MatrixGetter(v, 5); }
-float MatrixGetter6(const Dali::Matrix &v) { return MatrixGetter(v, 6); }
-float MatrixGetter7(const Dali::Matrix &v) { return MatrixGetter(v, 7); }
-float MatrixGetter8(const Dali::Matrix &v) { return MatrixGetter(v, 8); }
-float MatrixGetter9(const Dali::Matrix &v) { return MatrixGetter(v, 9); }
-float MatrixGetter10(const Dali::Matrix &v) { return MatrixGetter(v,10); }
-float MatrixGetter11(const Dali::Matrix &v) { return MatrixGetter(v,11); }
-float MatrixGetter12(const Dali::Matrix &v) { return MatrixGetter(v,12); }
-float MatrixGetter13(const Dali::Matrix &v) { return MatrixGetter(v,13); }
-float MatrixGetter14(const Dali::Matrix &v) { return MatrixGetter(v,14); }
-float MatrixGetter15(const Dali::Matrix &v) { return MatrixGetter(v,15); }
-float MatrixGetter16(const Dali::Matrix &v) { return MatrixGetter(v,16); }
-
-void MatrixSetter0(Dali::Matrix &v, float f) { MatrixSetter(v, f, 0); }
-void MatrixSetter1(Dali::Matrix &v, float f) { MatrixSetter(v, f, 1); }
-void MatrixSetter2(Dali::Matrix &v, float f) { MatrixSetter(v, f, 2); }
-void MatrixSetter3(Dali::Matrix &v, float f) { MatrixSetter(v, f, 3); }
-void MatrixSetter4(Dali::Matrix &v, float f) { MatrixSetter(v, f, 4); }
-void MatrixSetter5(Dali::Matrix &v, float f) { MatrixSetter(v, f, 5); }
-void MatrixSetter6(Dali::Matrix &v, float f) { MatrixSetter(v, f, 6); }
-void MatrixSetter7(Dali::Matrix &v, float f) { MatrixSetter(v, f, 7); }
-void MatrixSetter8(Dali::Matrix &v, float f) { MatrixSetter(v, f, 8); }
-void MatrixSetter9(Dali::Matrix &v, float f) { MatrixSetter(v, f, 9); }
-void MatrixSetter10(Dali::Matrix &v, float f) { MatrixSetter(v, f,10); }
-void MatrixSetter11(Dali::Matrix &v, float f) { MatrixSetter(v, f,11); }
-void MatrixSetter12(Dali::Matrix &v, float f) { MatrixSetter(v, f,12); }
-void MatrixSetter13(Dali::Matrix &v, float f) { MatrixSetter(v, f,13); }
-void MatrixSetter14(Dali::Matrix &v, float f) { MatrixSetter(v, f,14); }
-void MatrixSetter15(Dali::Matrix &v, float f) { MatrixSetter(v, f,15); }
-void MatrixSetter16(Dali::Matrix &v, float f) { MatrixSetter(v, f,16); }
-
-float Matrix3Getter0(const Dali::Matrix3 &v) { return MatrixGetter(v, 0); }
-float Matrix3Getter1(const Dali::Matrix3 &v) { return MatrixGetter(v, 1); }
-float Matrix3Getter2(const Dali::Matrix3 &v) { return MatrixGetter(v, 2); }
-float Matrix3Getter3(const Dali::Matrix3 &v) { return MatrixGetter(v, 3); }
-float Matrix3Getter4(const Dali::Matrix3 &v) { return MatrixGetter(v, 4); }
-float Matrix3Getter5(const Dali::Matrix3 &v) { return MatrixGetter(v, 5); }
-float Matrix3Getter6(const Dali::Matrix3 &v) { return MatrixGetter(v, 6); }
-float Matrix3Getter7(const Dali::Matrix3 &v) { return MatrixGetter(v, 7); }
-float Matrix3Getter8(const Dali::Matrix3 &v) { return MatrixGetter(v, 8); }
-
-void Matrix3Setter0(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 0); }
-void Matrix3Setter1(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 1); }
-void Matrix3Setter2(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 2); }
-void Matrix3Setter3(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 3); }
-void Matrix3Setter4(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 4); }
-void Matrix3Setter5(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 5); }
-void Matrix3Setter6(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 6); }
-void Matrix3Setter7(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 7); }
-void Matrix3Setter8(Dali::Matrix3 &v, float f) { MatrixSetter(v, f, 8); }
-
-val JavascriptUpdateCallback( val::undefined() );
-bool JavascriptUpdateCallbackSet = false;
-
-void JavascriptUpdate(int dt)
-{
- if( JavascriptUpdateCallbackSet )
- {
- JavascriptUpdateCallback( val(dt) );
- }
-}
-
-void SetUpdateFunction( const emscripten::val& function )
-{
- JavascriptUpdateCallback = function;
- JavascriptUpdateCallbackSet = true;
-}
-
-const emscripten::val& GetUpdateFunction()
-{
- return JavascriptUpdateCallback;
-}
-
-/**
- * Emscripten Bindings
- *
- * This uses Emscripten 'bind' (similar in design to Boost's python wrapper library).
- * It provides a simplified way to wrap C++ classes and wraps Emscriptens type
- * registration API.
- *
- * A convention below is that where there is a function or method name prepended
- * with '__' there is a corresponding Javascript helper function to help with
- * marshalling parameters and return values.
- *
- */
-EMSCRIPTEN_BINDINGS(dali_wrapper)
-{
- // With a little help embind knows about vectors so we tell it which ones to instantiate
- register_dali_vector<int>("DaliVectorInt");
- register_vector<std::string>("VectorString");
- register_vector<int>("VectorInt");
- register_vector<float>("VectorFloat");
- register_vector<Dali::Actor>("VectorActor");
-
- //
- // Creation functions.
- //
- emscripten::function("VersionString", &VersionString);
- emscripten::function("__createActor", &CreateActor);
- emscripten::function("__createHandle", &CreateHandle);
- emscripten::function("__createSolidColorActor", &CreateSolidColorActor);
-
- //
- // Helper functions
- //
- emscripten::function("javascriptValue", &JavascriptValue);
- emscripten::function("__hitTest", &HitTest);
- emscripten::function("sendMouseEvent", &EmscriptenMouseEvent);
- emscripten::function("__updateOnce", &EmscriptenUpdateOnce);
- emscripten::function("__renderOnce", &EmscriptenRenderOnce);
- emscripten::function("generateControlPoints", &GenerateControlPoints);
-
- //
- // Global callback functions
- //
- emscripten::function("setCallbackGetGlyphImage", &SetCallbackGetGlyphImage);
- emscripten::function("setCallbackGetImage", &SetCallbackGetImage);
- emscripten::function("setCallbackGetImageMetadata", &SetCallbackGetImageMetadata);
- emscripten::function("setCallbackRenderFinished", &SetCallbackRenderFinished);
- emscripten::function("setUpdateFunction", &SetUpdateFunction);
- emscripten::function("getUpdateFunction", &GetUpdateFunction);
-
- //
- // Property value creation (Javascript can't select on type)
- //
- emscripten::function("PropertyValueBoolean", &PropertyValueBoolean);
- emscripten::function("PropertyValueFloat", &PropertyValueFloat);
- emscripten::function("PropertyValueInteger", &PropertyValueInteger);
- emscripten::function("PropertyValueString", &PropertyValueString);
- emscripten::function("PropertyValueVector2", &PropertyValueVector2);
- emscripten::function("PropertyValueVector3", &PropertyValueVector3);
- emscripten::function("PropertyValueVector4", &PropertyValueVector4);
- emscripten::function("PropertyValueMatrix", &PropertyValueMatrix);
- emscripten::function("PropertyValueMatrix3", &PropertyValueMatrix3);
- emscripten::function("PropertyValueMap", &PropertyValueContainer);
- emscripten::function("PropertyValueArray", &PropertyValueContainer);
- emscripten::function("PropertyValueEuler", &PropertyValueEuler);
- emscripten::function("PropertyValueAxisAngle", &PropertyValueAxisAngle);
- emscripten::function("PropertyValueString", &PropertyValueString);
- emscripten::function("PropertyValueIntRect", &PropertyValueIntRect);
-
- //
- // One unfortunate aspect of wrapping for the browser is that we get no notification
- // of object deletion so all JS wrapper objects must be wrapper.delete() correctly.
- //
- // Embind has a mechanism around this for simple c style structs decared as value_arrays.
- // These are immediately transformed to Javascript arrays and don't need explicit
- // destruction, however the API needs a member offset.
- //
- value_array<Dali::Internal::Emscripten::Statistics>("Statistics")
- .element(&Dali::Internal::Emscripten::Statistics::on)
- .element(&Dali::Internal::Emscripten::Statistics::frameCount)
- .element(&Dali::Internal::Emscripten::Statistics::lastFrameDeltaSeconds)
- .element(&Dali::Internal::Emscripten::Statistics::lastSyncTimeMilliseconds)
- .element(&Dali::Internal::Emscripten::Statistics::nextSyncTimeMilliseconds)
- .element(&Dali::Internal::Emscripten::Statistics::keepUpdating)
- .element(&Dali::Internal::Emscripten::Statistics::needsNotification)
- .element(&Dali::Internal::Emscripten::Statistics::secondsFromLastFrame)
-;
-
- value_array<Dali::Vector2>("Vector2")
- .element(&Dali::Vector2::x)
- .element(&Dali::Vector2::y)
-;
-
- value_array<Dali::Vector3>("Vector3")
- .element(&Dali::Vector3::x)
- .element(&Dali::Vector3::y)
- .element(&Dali::Vector3::z)
-;
-
- value_array<Dali::Vector4>("Vector4")
- .element(&Dali::Vector4::x)
- .element(&Dali::Vector4::y)
- .element(&Dali::Vector4::z)
- .element(&Dali::Vector4::w)
-;
-
- value_array<Dali::Matrix>("Matrix")
- .element(&MatrixGetter0, &MatrixSetter0)
- .element(&MatrixGetter1, &MatrixSetter1)
- .element(&MatrixGetter2, &MatrixSetter2)
- .element(&MatrixGetter3, &MatrixSetter3)
- .element(&MatrixGetter4, &MatrixSetter4)
- .element(&MatrixGetter5, &MatrixSetter5)
- .element(&MatrixGetter6, &MatrixSetter6)
- .element(&MatrixGetter7, &MatrixSetter7)
- .element(&MatrixGetter8, &MatrixSetter8)
- .element(&MatrixGetter9, &MatrixSetter9)
- .element(&MatrixGetter10, &MatrixSetter10)
- .element(&MatrixGetter11, &MatrixSetter11)
- .element(&MatrixGetter12, &MatrixSetter12)
- .element(&MatrixGetter13, &MatrixSetter13)
- .element(&MatrixGetter14, &MatrixSetter14)
- .element(&MatrixGetter15, &MatrixSetter15)
-;
-
- value_array<Dali::Matrix3>("Matrix3")
- .element(&Matrix3Getter0, &Matrix3Setter0)
- .element(&Matrix3Getter1, &Matrix3Setter1)
- .element(&Matrix3Getter2, &Matrix3Setter2)
- .element(&Matrix3Getter3, &Matrix3Setter3)
- .element(&Matrix3Getter4, &Matrix3Setter4)
- .element(&Matrix3Getter5, &Matrix3Setter5)
- .element(&Matrix3Getter6, &Matrix3Setter6)
- .element(&Matrix3Getter7, &Matrix3Setter7)
- .element(&Matrix3Getter8, &Matrix3Setter8)
-;
-
- //
- // enums
- //
- enum_<Dali::Property::Type>("PropertyType")
- .value("NONE", Dali::Property::NONE)
- .value("BOOLEAN", Dali::Property::BOOLEAN)
- .value("FLOAT", Dali::Property::FLOAT)
- .value("INTEGER", Dali::Property::INTEGER)
- .value("VECTOR2", Dali::Property::VECTOR2)
- .value("VECTOR3", Dali::Property::VECTOR3)
- .value("VECTOR4", Dali::Property::VECTOR4)
- .value("MATRIX3", Dali::Property::MATRIX3)
- .value("MATRIX", Dali::Property::MATRIX)
- .value("RECTANGLE", Dali::Property::RECTANGLE)
- .value("ROTATION", Dali::Property::ROTATION)
- .value("STRING", Dali::Property::STRING)
- .value("ARRAY", Dali::Property::ARRAY)
- .value("MAP", Dali::Property::MAP)
-;
-
- enum_<Dali::Shader::Hint::Value>("ShaderHints")
- .value("NONE", Dali::Shader::Hint::NONE)
- .value("OUTPUT_IS_TRANSPARENT", Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT)
- .value("MODIFIES_GEOMETRY", Dali::Shader::Hint::MODIFIES_GEOMETRY)
-;
-
- enum_<Dali::Animation::EndAction>("EndAction")
- .value("Bake", Dali::Animation::Bake)
- .value("Discard", Dali::Animation::Discard)
- .value("BakeFinal", Dali::Animation::BakeFinal)
-;
-
- enum_<Dali::Animation::Interpolation>("Interpolation")
- .value("Linear", Dali::Animation::Interpolation::Linear)
- .value("Cubic", Dali::Animation::Interpolation::Cubic)
-;
-
- enum_<Dali::Geometry::Type>("Type")
- .value("POINTS", Dali::Geometry::POINTS)
- .value("LINES", Dali::Geometry::LINES)
- .value("LINE_LOOP", Dali::Geometry::LINE_LOOP)
- .value("LINE_STRIP", Dali::Geometry::LINE_STRIP)
- .value("TRIANGLES", Dali::Geometry::TRIANGLES)
- .value("TRIANGLE_FAN", Dali::Geometry::TRIANGLE_FAN)
- .value("TRIANGLE_STRIP", Dali::Geometry::TRIANGLE_STRIP)
-;
-
- enum_<Dali::Pixel::Format>("PixelFormat")
- .value("A8", Dali::Pixel::Format::A8)
- .value("L8", Dali::Pixel::Format::L8)
- .value("LA88", Dali::Pixel::Format::LA88)
- .value("RGB565", Dali::Pixel::Format::RGB565)
- .value("BGR565", Dali::Pixel::Format::BGR565)
- .value("RGBA4444", Dali::Pixel::Format::RGBA4444)
- .value("BGRA4444", Dali::Pixel::Format::BGRA4444)
- .value("RGBA5551", Dali::Pixel::Format::RGBA5551)
- .value("BGRA5551", Dali::Pixel::Format::BGRA5551)
- .value("RGB888", Dali::Pixel::Format::RGB888)
- .value("RGB8888", Dali::Pixel::Format::RGB8888)
- .value("BGR8888", Dali::Pixel::Format::BGR8888)
- .value("RGBA8888", Dali::Pixel::Format::RGBA8888)
- .value("BGRA8888", Dali::Pixel::Format::BGRA8888)
- // GLES 3 Standard compressed formats:
- .value("COMPRESSED_R11_EAC", Dali::Pixel::Format::COMPRESSED_R11_EAC)
- .value("COMPRESSED_SIGNED_R11_EAC", Dali::Pixel::Format::COMPRESSED_SIGNED_R11_EAC)
- .value("COMPRESSED_RG11_EAC", Dali::Pixel::Format::COMPRESSED_RG11_EAC)
- .value("COMPRESSED_SIGNED_RG11_EAC", Dali::Pixel::Format::COMPRESSED_SIGNED_RG11_EAC)
- .value("COMPRESSED_RGB8_ETC2", Dali::Pixel::Format::COMPRESSED_RGB8_ETC2)
- .value("COMPRESSED_SRGB8_ETC2", Dali::Pixel::Format::COMPRESSED_SRGB8_ETC2)
- .value("COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2", Dali::Pixel::Format::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2)
- .value("COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2", Dali::Pixel::Format::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2)
- .value("COMPRESSED_RGBA8_ETC2_EAC", Dali::Pixel::Format::COMPRESSED_RGBA8_ETC2_EAC)
- .value("COMPRESSED_SRGB8_ALPHA8_ETC2_EAC", Dali::Pixel::Format::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)
- // GLES 2 extension compressed formats:
- .value("COMPRESSED_RGB8_ETC1", Dali::Pixel::Format::COMPRESSED_RGB8_ETC1)
- .value("COMPRESSED_RGB_PVRTC_4BPPV1", Dali::Pixel::Format::COMPRESSED_RGB_PVRTC_4BPPV1)
-;
-
- enum_<Dali::FaceCullingMode::Type>("FaceCullingMode")
- .value("NONE", Dali::FaceCullingMode::NONE)
- .value("FRONT", Dali::FaceCullingMode::FRONT)
- .value("BACK", Dali::FaceCullingMode::BACK)
- .value("FRONT_AND_BACK", Dali::FaceCullingMode::FRONT_AND_BACK)
-;
-
- enum_<Dali::DepthWriteMode::Type>("DepthWriteMode")
- .value("OFF", Dali::DepthWriteMode::OFF)
- .value("AUTO", Dali::DepthWriteMode::AUTO)
- .value("ON", Dali::DepthWriteMode::ON)
-;
-
- enum_<Dali::BlendMode::Type>("BlendMode")
- .value("OFF", Dali::BlendMode::OFF)
- .value("AUTO", Dali::BlendMode::AUTO)
- .value("ON", Dali::BlendMode::ON)
-;
-
- enum_<Dali::AlphaFunction::BuiltinFunction>("AlphaFunction")
- .value("DEFAULT", Dali::AlphaFunction::BuiltinFunction::DEFAULT)
- .value("LINEAR", Dali::AlphaFunction::BuiltinFunction::LINEAR)
- .value("REVERSE", Dali::AlphaFunction::BuiltinFunction::REVERSE)
- .value("EASE_IN_SQUARE", Dali::AlphaFunction::BuiltinFunction::EASE_IN_SQUARE)
- .value("EASE_OUT_SQUARE", Dali::AlphaFunction::BuiltinFunction::EASE_OUT_SQUARE)
- .value("EASE_IN", Dali::AlphaFunction::BuiltinFunction::EASE_IN)
- .value("EASE_OUT", Dali::AlphaFunction::BuiltinFunction::EASE_OUT)
- .value("EASE_IN_OUT", Dali::AlphaFunction::BuiltinFunction::EASE_IN_OUT)
- .value("EASE_IN_SINE", Dali::AlphaFunction::BuiltinFunction::EASE_IN_SINE)
- .value("EASE_OUT_SINE", Dali::AlphaFunction::BuiltinFunction::EASE_OUT_SINE)
- .value("EASE_IN_OUT_SINE", Dali::AlphaFunction::BuiltinFunction::EASE_IN_OUT_SINE)
- .value("BOUNCE", Dali::AlphaFunction::BuiltinFunction::BOUNCE)
- .value("SIN", Dali::AlphaFunction::BuiltinFunction::SIN)
- .value("EASE_OUT_BACK", Dali::AlphaFunction::BuiltinFunction::EASE_OUT_BACK)
-;
-
- //
- // classes
- //
-
- // we need property map as an object rather than straight conversion to javascript 'object'
- // because its ordered. And PropertyBuffer needs an order.
- class_<Dali::Property::Map>("PropertyMap")
- .constructor<>()
- .function("count", &Dali::Property::Map::Count)
- .function("empty", &Dali::Property::Map::Empty)
- .function("__insert", select_overload< void(const std::string&, const Dali::Property::Value&) > (&Dali::Property::Map::Insert))
- .function("__get", &PropertyMapGet)
- .function("__getValue", &Dali::Property::Map::GetValue)
- .function("getKey", &Dali::Property::Map::GetKey)
- .function("clear", &Dali::Property::Map::Clear)
- .function("merge", &Dali::Property::Map::Merge)
-;
-
- class_<Dali::Property::Value>("PropertyValue")
- .constructor<>()
- .function("getType", &PropertyGetType)
- .function("getTypeName", &PropertyGetTypeName)
- .function("getBoolean", &PropertyGetBoolean)
- .function("getFloat", &PropertyGetFloat)
- .function("getInteger", &PropertyGetInteger)
- .function("getVector2", &PropertyGetVector2)
- .function("getVector3", &PropertyGetVector3)
- .function("getVector4", &PropertyGetVector4)
- .function("getString", &PropertyGetString)
- .function("getMap", &PropertyGetMap)
- .function("getArray", &PropertyGetArray)
- .function("getMatrix", &PropertyGetMatrix)
- .function("getMatrix3", &PropertyGetMatrix3)
- .function("getEuler", &PropertyGetEuler)
- .function("getRotation", &PropertyGetRotation)
- .function("getIntRect", &PropertyGetIntRect)
-;
-
- class_<Dali::BaseHandle>("BaseHandle")
- .function("ok", &BaseHandleOk)
- .function("getTypeName", &BaseHandle::GetTypeName)
-;
-
- class_<Dali::TypeInfo, base<Dali::BaseHandle>>("TypeInfo")
- .function("getName", &Dali::TypeInfo::GetName)
- .function("getBaseName", &Dali::TypeInfo::GetBaseName)
- .function("getProperties", &GetAllProperties)
- .function("getActions", &GetActions)
- .function("getSignals", &GetSignals)
- .function("getPropertyIndices", &Dali::TypeInfo::GetPropertyIndices)
-;
-
- class_<Dali::TypeRegistry>("TypeRegistry")
- .constructor<>(&Dali::TypeRegistry::Get)
- .function("getTypeNameCount", &Dali::TypeRegistry::GetTypeNameCount)
- .function("getTypeName", &Dali::TypeRegistry::GetTypeName)
- .function("getTypeInfo", select_overload< Dali::TypeInfo(const std::string&) > (&Dali::TypeRegistry::GetTypeInfo))
-;
-
- class_<SignalHolder>("SignalHolder")
- .constructor<>()
-;
-
- class_<Dali::Handle, base<Dali::BaseHandle>>("Handle")
- .function("__registerProperty", &RegisterProperty)
- .function("__registerAnimatedProperty", &RegisterAnimatedProperty)
- .function("setSelf", &SetSelf)
- .function("setProperty", &SetProperty)
- .function("getProperty", &GetProperty)
- .function("getPropertyIndex", &GetPropertyIndex)
- .function("getProperties", &GetProperties)
- .function("getPropertyIndices", &Handle::GetPropertyIndices)
- .function("getPropertyTypeFromName", &GetPropertyTypeFromName)
- .function("getPropertyTypeName", &GetPropertyTypeName)
- .function("registerProperty", &RegisterProperty)
- .function("registerAnimatedProperty", &RegisterAnimatedProperty)
- .function("getTypeInfo", &GetTypeInfo)
- .function("isPropertyWritable", &Handle::IsPropertyWritable)
- .function("isPropertyAnimatable", &Handle::IsPropertyAnimatable)
- .function("isPropertyAConstraintInput", &Handle::IsPropertyAConstraintInput)
-;
-
- class_<Dali::Path, base<Dali::Handle>>("Path")
- .constructor<>(&Dali::Path::New)
- .function("addPoint", &Dali::Path::AddPoint)
- .function("addControlPoint", &Dali::Path::AddControlPoint)
- .function("generateControlPoints", &Dali::Path::GenerateControlPoints)
- .function("sample", &Dali::Path::Sample)
- .function("getPoint", &Dali::Path::GetPoint)
- .function("getControlPoint", &Dali::Path::GetControlPoint)
- .function("getPointCount", &Dali::Path::GetPointCount)
-;
-
- class_<Dali::KeyFrames>("KeyFrames")
- .constructor<>(&Dali::KeyFrames::New)
- .function("add", select_overload<void (float progress, Property::Value value)>(&Dali::KeyFrames::Add))
- .function("addWithAlpha", &KeyFramesAddWithAlpha)
-;
-
- class_<Dali::Animation>("Animation")
- .constructor<float>(&Dali::Animation::New)
- .function("__animateTo", &AnimateTo)
- .function("__animateBy", &AnimateBy)
- .function("__animateBetween", &AnimateBetween)
- .function("__animatePath", &AnimatePath)
- .function("setDuration", &Dali::Animation::SetDuration)
- .function("getDuration", &Dali::Animation::GetDuration)
- .function("setLooping", &Dali::Animation::SetLooping)
- .function("isLooping", &Dali::Animation::IsLooping)
- .function("setEndAction", &Dali::Animation::SetEndAction)
- .function("getEndAction", &Dali::Animation::GetEndAction)
- .function("setDisconnectAction", &Dali::Animation::SetDisconnectAction)
- .function("getDisconnectAction", &Dali::Animation::GetDisconnectAction)
- .function("setCurrentProgress", &Dali::Animation::SetCurrentProgress)
- .function("getCurrentProgress", &Dali::Animation::GetCurrentProgress)
- .function("setSpeedFactor", &Dali::Animation::SetSpeedFactor)
- .function("getSpeedFactor", &Dali::Animation::GetSpeedFactor)
- .function("setPlayRange", &Dali::Animation::SetPlayRange)
- .function("getPlayRange", &Dali::Animation::GetPlayRange)
- .function("play", &Dali::Animation::Play)
- .function("playFrom", &Dali::Animation::PlayFrom)
- .function("pause", &Dali::Animation::Pause)
- .function("stop", &Dali::Animation::Stop)
- .function("clear", &Dali::Animation::Clear)
-;
-
- class_<Dali::PropertyBuffer>("PropertyBuffer")
- .constructor<Dali::Property::Map&>(Dali::PropertyBuffer::New)
- .function("setData", &SetPropertyBufferDataRaw)
-;
-
- class_<Dali::Geometry>("Geometry")
- .constructor<>(&Dali::Geometry::New)
- .function("addVertexBuffer", &Dali::Geometry::AddVertexBuffer)
- .function("getNumberOfVertexBuffers", &Dali::Geometry::GetNumberOfVertexBuffers)
- .function("setIndexBuffer", &SetIndexBufferDataRaw)
- .function("setType", &Dali::Geometry::SetType)
- .function("getType", &Dali::Geometry::GetType)
-;
-
- class_<Dali::Image>("Image")
-;
-
- class_<Dali::BufferImage, base<Dali::Image> >("BufferImage")
- .constructor<const std::string&, unsigned int, unsigned int, Dali::Pixel::Format>(&BufferImageNew)
-;
-
- class_<Dali::EncodedBufferImage, base<Dali::Image> >("EncodedBufferImage")
- .constructor<const std::string&>(&EncodedBufferImageNew)
-;
-
- class_<Dali::Sampler>("Sampler")
- .constructor<>(&Dali::Sampler::New)
-;
-
- class_<Dali::Shader, base<Dali::Handle>>("Shader")
- .constructor<>(&Dali::Shader::New)
-;
-
- class_<Dali::TextureSet>("TextureSet")
- .constructor<>(&Dali::TextureSet::New)
- .function("setTexture", &Dali::TextureSet::SetTexture)
- .function("setSampler", &Dali::TextureSet::SetSampler)
- .function("getTexture", &Dali::TextureSet::GetTexture)
- .function("getSampler", &Dali::TextureSet::GetSampler)
- .function("getTextureCount", &Dali::TextureSet::GetTextureCount)
-;
-
- class_<Dali::Renderer, base<Dali::Handle>>("Renderer")
- .constructor<>(&Dali::Renderer::New)
- .function("setGeometry", &Dali::Renderer::SetGeometry)
- .function("getGeometry", &Dali::Renderer::GetGeometry)
- .function("SetTextures", &Dali::Renderer::SetTextures)
- .function("SetTextures", &Dali::Renderer::SetTextures)
-;
-
- class_<Dali::Actor, base<Dali::Handle>>("Actor")
- .constructor<>(&Dali::Actor::New)
- .function("add", &Dali::Actor::Add)
- .function("remove", &Dali::Actor::Remove)
- .function("getId", &Dali::Actor::GetId)
- .function("__getParent", &Dali::Actor::GetParent)
- .function("__findChildById", &Dali::Actor::FindChildById)
- .function("__findChildByName", &Dali::Actor::FindChildByName)
- .function("__getChildAt", &Dali::Actor::GetChildAt)
- .function("getChildCount", &Dali::Actor::GetChildCount)
- .function("__screenToLocal",
- select_overload<std::vector<float> (Dali::Actor, float, float)>(&ScreenToLocal))
- .function("addressOf", &AddressOf)
- .function("__connect", &ConnectSignal)
- .function("__setPropertyNotification", &SetPropertyNotification)
- .function("addRenderer", &Dali::Actor::AddRenderer)
- .function("getRendererCount", &Dali::Actor::GetRendererCount)
- .function("removeRenderer",
- select_overload<void(unsigned int)>(&Dali::Actor::RemoveRenderer))
- .function("__getRendererAt", &Dali::Actor::GetRendererAt)
-;
-
- class_<Dali::CameraActor, base<Dali::Actor>>("CameraActor")
- .constructor<>( select_overload<Dali::CameraActor()>(&Dali::CameraActor::New))
-;
-
- class_<Dali::Layer, base<Dali::Actor>>("Layer")
- .constructor<>(&Dali::Layer::New)
- .function("raise", &Dali::Layer::Raise)
- .function("lower", &Dali::Layer::Lower)
-;
-
- class_<Dali::Stage>("Stage")
- .constructor<>(&Dali::Stage::GetCurrent)
- .function("add", &Dali::Stage::Add)
- .function("remove", &Dali::Stage::Remove)
- .function("__getRootLayer", &Dali::Stage::GetRootLayer)
- .function("getLayer", &Dali::Stage::GetLayer)
- .function("getRenderTaskList", &Dali::Stage::GetRenderTaskList)
- .function("setBackgroundColor", &Dali::Stage::SetBackgroundColor)
-;
-
- class_<Dali::RenderTaskList>("RenderTaskList")
- .function("createTask", &Dali::RenderTaskList::CreateTask)
- .function("removeTask", &Dali::RenderTaskList::RemoveTask)
- .function("getTaskCount", &Dali::RenderTaskList::GetTaskCount)
- .function("getTask", &Dali::RenderTaskList::GetTask)
-;
-
- class_<Dali::RenderTask>("RenderTask")
- .function("__getCameraActor", &Dali::RenderTask::GetCameraActor)
- .function("setCameraActor", &Dali::RenderTask::SetCameraActor)
- .function("setSourceActor", &Dali::RenderTask::SetSourceActor)
- .function("setExclusive", &Dali::RenderTask::SetExclusive)
- .function("setInputEnabled", &Dali::RenderTask::SetInputEnabled)
- .function("setViewportPosition", &Dali::RenderTask::SetViewportPosition)
- .function("setViewportSize", &Dali::RenderTask::SetViewportSize)
- .function("getCurrentViewportPosition", &Dali::RenderTask::GetCurrentViewportPosition)
- .function("getCurrentViewportSize", &Dali::RenderTask::GetCurrentViewportSize)
- .function("setClearColor", &Dali::RenderTask::SetClearColor)
- .function("getClearColor", &Dali::RenderTask::GetClearColor)
- .function("setClearEnabled", &Dali::RenderTask::SetClearEnabled)
- .function("getClearEnabled", &Dali::RenderTask::GetClearEnabled)
- .function("screenToLocal",
- select_overload<Dali::Vector2(Dali::RenderTask, Dali::Actor, float, float)>(&ScreenToLocal))
- .function("worldToScreen", &WorldToScreen)
-;
-
-}
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-/*
- * Copyright (c) 2016 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.
- *
- */
-
-/* eslint-env browser */
-/* eslint "brace-style": [2, "1tbs"] */
-/* eslint "no-console": 0 */
-/* eslint "no-underscore-dangle": 0 */
-
-/*******************************************************************************
- *
- * The javascript counterpart to the C++ DALi wrapper.
- *
- * Provides helper functionality to make the use of the dali module.
- *
- * Where possible it creates a natural Javascript API. One problem
- * is that wrapped C++ objects must be explicitly deleted '<obj>.delete()'.
- * This is because javascript in the browser has no available hook to watch
- * for an objects destruction.
- *
- * This file combines several 'Modules' and could be split when using a
- * a recombining web build tool.
- *
- *
- ******************************************************************************/
-
-// forward refs for lint
-var Module;
-// On upgrading to emscripten 1.34.2 and -s EXPORT_NAME="dali" on emcc command
-// line no longer seems to work so set it here.
-var dali = Module;
-var document;
-var console;
-
-//------------------------------------------------------------------------------
-//
-// Math Module
-//
-//------------------------------------------------------------------------------
-
-/**
- * Matrix Multiplication
- * @method matrixByMatrix
- * @param {Array} A Matrix4 array
- * @param {Array} B Matrix4 array
- * @return {Array} Matrix4
- */
-dali.matrixByMatrix = function(A, B) {
- "use strict";
-
- var ret = [1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- ];
-
- ret[0] = A[0] * B[0] + A[1] * B[4] + A[2] * B[8] + A[3] * B[12];
- ret[4] = A[4] * B[0] + A[5] * B[4] + A[6] * B[8] + A[7] * B[12];
- ret[8] = A[8] * B[0] + A[9] * B[4] + A[10] * B[8] + A[11] * B[12];
- ret[12] = A[12] * B[0] + A[13] * B[4] + A[14] * B[8] + A[15] * B[12];
-
- ret[1] = A[0] * B[1] + A[1] * B[5] + A[2] * B[9] + A[3] * B[13];
- ret[5] = A[4] * B[1] + A[5] * B[5] + A[6] * B[9] + A[7] * B[13];
- ret[9] = A[8] * B[1] + A[9] * B[5] + A[10] * B[9] + A[11] * B[13];
- ret[13] = A[12] * B[1] + A[13] * B[5] + A[14] * B[9] + A[15] * B[13];
-
- ret[2] = A[0] * B[2] + A[1] * B[6] + A[2] * B[10] + A[3] * B[14];
- ret[6] = A[4] * B[2] + A[5] * B[6] + A[6] * B[10] + A[7] * B[14];
- ret[10] = A[8] * B[2] + A[9] * B[6] + A[10] * B[10] + A[11] * B[14];
- ret[14] = A[12] * B[2] + A[13] * B[6] + A[14] * B[10] + A[15] * B[14];
-
- ret[3] = A[0] * B[3] + A[1] * B[7] + A[2] * B[11] + A[3] * B[15];
- ret[7] = A[4] * B[3] + A[5] * B[7] + A[6] * B[11] + A[7] * B[15];
- ret[11] = A[8] * B[3] + A[9] * B[7] + A[10] * B[11] + A[11] * B[15];
- ret[15] = A[12] * B[3] + A[13] * B[7] + A[14] * B[11] + A[15] * B[15];
-
- return ret;
-};
-
-/**
- * Matrix Vector4 Multiplication
- * @method matrixByVector
- * @param {Array} A Matrix4 array
- * @param {Array} v Vector4
- * @return {Array} Vector4
- */
-dali.matrixByVector = function(A, v) {
- "use strict";
-
- var x = v[0];
- var y = v[1];
- var z = v[2];
- var w = 1;
-
- if (v.length === 4) {
- w = v[3];
- }
-
- return [
- A[0] * x + A[4] * y + A[8] * z + A[12] * w,
- A[1] * x + A[5] * y + A[9] * z + A[13] * w,
- A[2] * x + A[6] * y + A[10] * z + A[14] * w,
- A[3] * x + A[7] * y + A[11] * z + A[15] * w
- ];
-};
-
-/**
- * Get Matrix Determinant
- * @method matrixDeterminant
- * @param {Array} A Matrix4 array
- * @return {float} Determinant
- */
-dali.matrixDeterminant = function(A) {
- "use strict";
-
- var n11 = A[0],
- n12 = A[4],
- n13 = A[8],
- n14 = A[12];
- var n21 = A[1],
- n22 = A[5],
- n23 = A[9],
- n24 = A[13];
- var n31 = A[2],
- n32 = A[6],
- n33 = A[10],
- n34 = A[14];
- var n41 = A[3],
- n42 = A[7],
- n43 = A[11],
- n44 = A[15];
-
- var m0 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
- var m4 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
- var m8 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
- var m12 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
-
- return n11 * m0 + n21 * m4 + n31 * m8 + n41 * m12;
-};
-
-/**
- * Matrix Multiplication by scalar
- * @method matrixByScalar
- * @param {Array} A Matrix4 array
- * @param {float} s float
- * @return {Array} Matrix4
- */
-dali.matrixByScalar = function(A, s) {
- "use strict";
- return [A[0] * s, A[1] * s, A[2] * s, A[3] * s,
- A[4] * s, A[5] * s, A[6] * s, A[7] * s,
- A[8] * s, A[9] * s, A[10] * s, A[11] * s,
- A[12] * s, A[13] * s, A[14] * s, A[15] * s
- ];
-};
-
-/**
- * Matrix Inverse. Raises if there is none.
- * @method matrixInverse
- * @param {Array} A Matrix4 array
- * @return {Array} Inverse Matrix4
- */
-dali.matrixInverse = function(A) {
- "use strict";
- var ret = [1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- ];
-
- ret[0] = A[5] * A[10] * A[15] - A[5] * A[11] * A[14] - A[9] * A[6] * A[15] + A[9] * A[7] * A[14] + A[13] * A[6] * A[11] - A[13] * A[7] * A[10];
- ret[4] = -A[4] * A[10] * A[15] + A[4] * A[11] * A[14] + A[8] * A[6] * A[15] - A[8] * A[7] * A[14] - A[12] * A[6] * A[11] + A[12] * A[7] * A[10];
- ret[8] = A[4] * A[9] * A[15] - A[4] * A[11] * A[13] - A[8] * A[5] * A[15] + A[8] * A[7] * A[13] + A[12] * A[5] * A[11] - A[12] * A[7] * A[9];
- ret[12] = -A[4] * A[9] * A[14] + A[4] * A[10] * A[13] + A[8] * A[5] * A[14] - A[8] * A[6] * A[13] - A[12] * A[5] * A[10] + A[12] * A[6] * A[9];
-
- ret[1] = -A[1] * A[10] * A[15] + A[1] * A[11] * A[14] + A[9] * A[2] * A[15] - A[9] * A[3] * A[14] - A[13] * A[2] * A[11] + A[13] * A[3] * A[10];
- ret[5] = A[0] * A[10] * A[15] - A[0] * A[11] * A[14] - A[8] * A[2] * A[15] + A[8] * A[3] * A[14] + A[12] * A[2] * A[11] - A[12] * A[3] * A[10];
- ret[9] = -A[0] * A[9] * A[15] + A[0] * A[11] * A[13] + A[8] * A[1] * A[15] - A[8] * A[3] * A[13] - A[12] * A[1] * A[11] + A[12] * A[3] * A[9];
- ret[13] = A[0] * A[9] * A[14] - A[0] * A[10] * A[13] - A[8] * A[1] * A[14] + A[8] * A[2] * A[13] + A[12] * A[1] * A[10] - A[12] * A[2] * A[9];
-
- ret[2] = A[1] * A[6] * A[15] - A[1] * A[7] * A[14] - A[5] * A[2] * A[15] + A[5] * A[3] * A[14] + A[13] * A[2] * A[7] - A[13] * A[3] * A[6];
- ret[6] = -A[0] * A[6] * A[15] + A[0] * A[7] * A[14] + A[4] * A[2] * A[15] - A[4] * A[3] * A[14] - A[12] * A[2] * A[7] + A[12] * A[3] * A[6];
- ret[10] = A[0] * A[5] * A[15] - A[0] * A[7] * A[13] - A[4] * A[1] * A[15] + A[4] * A[3] * A[13] + A[12] * A[1] * A[7] - A[12] * A[3] * A[5];
- ret[14] = -A[0] * A[5] * A[14] + A[0] * A[6] * A[13] + A[4] * A[1] * A[14] - A[4] * A[2] * A[13] - A[12] * A[1] * A[6] + A[12] * A[2] * A[5];
-
- ret[3] = -A[1] * A[6] * A[11] + A[1] * A[7] * A[10] + A[5] * A[2] * A[11] - A[5] * A[3] * A[10] - A[9] * A[2] * A[7] + A[9] * A[3] * A[6];
- ret[7] = A[0] * A[6] * A[11] - A[0] * A[7] * A[10] - A[4] * A[2] * A[11] + A[4] * A[3] * A[10] + A[8] * A[2] * A[7] - A[8] * A[3] * A[6];
- ret[11] = -A[0] * A[5] * A[11] + A[0] * A[7] * A[9] + A[4] * A[1] * A[11] - A[4] * A[3] * A[9] - A[8] * A[1] * A[7] + A[8] * A[3] * A[5];
- ret[15] = A[0] * A[5] * A[10] - A[0] * A[6] * A[9] - A[4] * A[1] * A[10] + A[4] * A[2] * A[9] + A[8] * A[1] * A[6] - A[8] * A[2] * A[5];
-
- var det = A[0] * ret[0] + A[1] * ret[4] + A[2] * ret[8] + A[3] * ret[12];
-
- if (det === 0) {
- throw "no inverse";
- }
-
- return dali.matrixByScalar(ret, 1 / det);
-};
-
-/**
- * Radian to degree
- * @method degree
- * @param {float} radians
- * @return {float} degrees
- */
-dali.degree = function(radians) {
- "use strict";
- return (radians * 180.0) / Math.PI;
-};
-
-/**
- * Degree to Radians
- * @method radian
- * @param {float} degree
- * @return {float} radian
- */
-dali.radian = function(degrees) {
- "use strict";
- return (degrees / 180.0) * Math.PI;
-};
-
-/**
- * Length of a vector
- * @method vectorLength
- * @param {array} Vector4
- * @return {float} The length of a vector
- */
-dali.vectorLength = function(array) {
- "use strict";
- var N = 3; // array.length;
-
- var length = 0;
- for (var i = 0; i < N; ++i) {
- length += array[i] * array[i];
- }
- return Math.sqrt(length);
-};
-
-/**
- * Length of a vector squared
- * @method vectorLengthSquared
- * @param {array} Vector4
- * @return {float} The length of a vector squared
- */
-dali.vectorLengthSquared = function(array) {
- "use strict";
- var N = 3; // array.length;
-
- var length = 0;
- for (var i = 0; i < N; ++i) {
- length += array[i] * array[i];
- }
- return length;
-};
-
-/**
- * Normalized vector
- * @method normalize
- * @param {array} Vector4
- * @return {float} The normalized vector
- */
-dali.normalize = function(array) {
- "use strict";
- var N = 3; // array.length;
-
- var length = 0;
- for (var i = 0; i < 3; ++i) {
- length += array[i] * array[i];
- }
- length = Math.sqrt(length);
-
- if (length !== 0) {
- var ret = [];
- for (i = 0; i < N; ++i) {
- ret.push(array[i] / length);
- }
- for (i = N; i < array.length; ++i) {
- ret.push(array[i]);
- }
- return ret;
- } else {
- return array;
- }
-
-};
-
-/**
- * AxisAngle conversion to Quaternion
- * @method axisAngleToQuaternion
- * @param {array} axisAngle Vector4 [Axis.x, Axis.y, Axis.z, Angle]
- * @return {array} Quaternion
- */
-dali.axisAngleToQuaternion = function(axisAngle) {
- "use strict";
- var an = dali.normalize(axisAngle);
- var angle = axisAngle[axisAngle.length - 1];
- var halfTheta = angle * 0.5;
- var sinThetaByTwo = Math.sin(halfTheta);
- var cosThetaByTwo = Math.cos(halfTheta);
- return [an[0] * sinThetaByTwo,
- an[1] * sinThetaByTwo,
- an[2] * sinThetaByTwo,
- cosThetaByTwo
- ];
-};
-
-/**
- * Vector3 dot product
- * @method vectorDot
- * @param {array} v1 Vector3
- * @param {array} v2 Vector3
- * @return {array} Quaternion
- */
-dali.vectorDot = function(v1, v2) {
- "use strict";
- return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
-};
-
-/**
- * Vector4 dot product
- * @method vectorDot
- * @param {array} v1 Vector4
- * @param {array} v2 Vector4
- * @return {float} Dot product
- */
-dali.vectorDot4 = function(v1, v2) {
- "use strict";
- return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
-};
-
-/**
- * Vector3 cross product
- * @method vectorCross
- * @param {array} v1 Vector3
- * @param {array} v2 Vector3
- * @return {array} Vector3 cross product
- */
-dali.vectorCross = function(v1, v2) {
- "use strict";
- var v1X = v1[0];
- var v1Y = v1[1];
- var v1Z = v1[2];
-
- var v2X = v2[0];
- var v2Y = v2[1];
- var v2Z = v2[2];
-
- return [v1Y * v2Z - v1Z * v2Y,
- v1Z * v2X - v1X * v2Z,
- v1X * v2Y - v1Y * v2X
- ];
-};
-
-/**
- * VectorN dot product
- * @method vectorByScalar
- * @param {array} v1 VectorN
- * @param {array} v2 VectorN
- * @return {array} VectorN * s
- */
-dali.vectorByScalar = function(v1, s) {
- "use strict";
- var ret = [];
- for (var i = 0, len = v1.length; i < len; i++) {
- ret.push(v1[i] * s);
- }
- return ret;
-};
-
-/**
- * VectorN dot product
- * @method vectorAdd
- * @param {array} v1 VectorN
- * @param {array} v2 VectorN
- * @param {array} ..vN VectorN
- * @return {array} v1 + v2 + ... + vN
- */
-dali.vectorAdd = function() {
- "use strict";
- var ret = arguments[0];
- var l = ret.length;
- for (var i = 1, len = arguments.length; i < len; i++) {
- var v = arguments[i];
- for (var j = 0; j < l; j++) {
- ret[j] += v[j];
- }
- }
- return ret;
-};
-
-/**
- * Quaternion by quaternion
- * @method quatByQuat
- * @param {array} q1 Quaternion
- * @param {array} q2 Quaternion
- * @return {array} Quaternion
- */
-dali.quatByQuat = function(q1, q2) {
- "use strict";
- var q1X = q1[0];
- var q1Y = q1[1];
- var q1Z = q1[2];
- var q1W = q1[3];
-
- var q2X = q2[0];
- var q2Y = q2[1];
- var q2Z = q2[2];
- var q2W = q2[3];
-
- return [q1Y * q2Z - q1Z * q2Y + q1W * q2X + q1X * q2W,
- q1Z * q2X - q1X * q2Z + q1W * q2Y + q1Y * q2W,
- q1X * q2Y - q1Y * q2X + q1W * q2Z + q1Z * q2W,
- q1W * q2W - dali.vectorDot(q1, q2)
- ];
-};
-
-/**
- * Quaternion to Vector4 Axis angle
- * @method quaternionToAxisAngle
- * @param {array} q Quaternion
- * @return {array} Vector4 [Axis.x, Axis.y, Axis.z, Angle]
- */
-dali.quaternionToAxisAngle = function(q) {
- "use strict";
- var angle = Math.acos(q[3]);
- var sine = Math.sin(angle);
-
- if (sine === 0.0) {
- throw "Cannot convert quaternion";
- }
-
- var sinfThetaInv = 1.0 / sine;
-
- return [q[0] * sinfThetaInv,
- q[1] * sinfThetaInv,
- q[2] * sinfThetaInv,
- angle * 2.0
- ];
-};
-
-/**
- * Euler angles to Quaternion
- * @method eulerToQuaternion
- * @param {float} rxPitch Euler radians pitch
- * @param {float} ryYaw Euler radians yaw
- * @param {float} rzRoll Euler radians roll
- * @return {array} Quaternion
- */
-dali.eulerToQuaternion = function(rXPitch, rYYaw, rZRoll)
-{
- var halfX = 0.5 * rXPitch;
- var halfY = 0.5 * rYYaw;
- var halfZ = 0.5 * rZRoll;
-
- var cosX2 = Math.cos(halfX);
- var cosY2 = Math.cos(halfY);
- var cosZ2 = Math.cos(halfZ);
-
- var sinX2 = Math.sin(halfX);
- var sinY2 = Math.sin(halfY);
- var sinZ2 = Math.sin(halfZ);
-
- return [ cosZ2 * cosY2 * sinX2 - sinZ2 * sinY2 * cosX2,
- cosZ2 * sinY2 * cosX2 + sinZ2 * cosY2 * sinX2,
- sinZ2 * cosY2 * cosX2 - cosZ2 * sinY2 * sinX2,
- cosZ2 * cosY2 * cosX2 + sinZ2 * sinY2 * sinX2 ];
-};
-
-/**
- * Euler angles to Vector4 Axis angle
- * @method eulerToAxisAngle
- * @param {float} eulerInDegrees
- * @return {array} Vector4 [Axis.x, Axis.y, Axis.z, Angle]
- */
-dali.eulerToAxisAngle = function(eulerInDegrees)
-{
- var q = dali.eulerToQuaternion(dali.radian(eulerInDegrees[0]),dali.radian(eulerInDegrees[1]), dali.radian(eulerInDegrees[2]));
- var aa = dali.quaternionToAxisAngle(q);
- aa[3] = dali.degree(aa[3]); // @todo - radian?
- return aa;
-};
-
-/**
- * Axis angle to Euler
- * @method axisAngleToEuler
- * @param {float} axisAngle [Axis.x, Axis.y, Axis.z, Angle]
- * @return {array} Vector4 [roll, pitch, yaw]
- */
-dali.axisAngleToEuler = function(axisAngle)
-{
- // presume return from dali.js is degrees
- axisAngle[3] = dali.radian(axisAngle[3]);
- var q = dali.axisAngleToQuaternion(axisAngle);
- return dali.quaternionToEuler(q).map(dali.degree);
-};
-
-/**
- * Euler angles to Vector4 Axis angle
- * @method quaternionToMatrix
- * @param {float} axisAngle [Axis.x, Axis.y, Axis.z, Angle]
- * @return {array} Vector4
- */
-dali.quaternionToMatrix = function(q) {
- "use strict";
- var x = q[0];
- var y = q[1];
- var z = q[2];
- var w = q[3];
- var xx = x * x;
- var yy = y * y;
- var zz = z * z;
- var xy = x * y;
- var xz = x * z;
- var wx = w * x;
- var wy = w * y;
- var wz = w * z;
- var yz = y * z;
-
- var m = [1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1];
-
- m[0] = 1.0 - 2.0 * (yy + zz);
- m[1] = 2.0 * (xy + wz);
- m[2] = 2.0 * (xz - wy);
- m[3] = 0.0;
-
- m[4] = 2.0 * (xy - wz);
- m[5] = 1.0 - 2.0 * (xx + zz);
- m[6] = 2.0 * (yz + wx);
- m[7] = 0.0;
-
- m[8] = 2.0 * (xz + wy);
- m[9] = 2.0 * (yz - wx);
- m[10] = 1.0 - 2.0 * (xx + yy);
- m[11] = 0.0;
-
- m[12] = 0.0;
- m[13] = 0.0;
- m[14] = 0.0;
- m[15] = 1.0;
-
- return m;
-};
-
-/**
- * Quaternion to Euler
- * @method quaternionToEuler
- * @param {array} q Quaternion
- * @return {array} Vector3 [roll, pitch, yaw]
- */
-dali.quaternionToEuler = function(q) {
- "use strict";
- var x = q[0];
- var y = q[1];
- var z = q[2];
- var w = q[3];
-
- var sqw = w * w;
- var sqx = x * x;
- var sqy = y * y;
- var sqz = z * z;
-
- return [ Math.atan2(2.0 * (y * z + x * w), -sqx - sqy + sqz + sqw),
- Math.asin(-2.0 * (x * z - y * w)),
- Math.atan2(2.0 * (x * y + z * w), sqx - sqy - sqz + sqw)];
-};
-
-
-/**
- * Gets screen coordinates of world position
- * @method worldToScreen
- * @param {array} position array
- * @param {Dali.RenderTask} renderTask Dali RenderTask object
- * @return {array} Vector3 Screen position
- */
-dali.worldToScreen = function(position, renderTask) {
- "use strict";
- var useFirstRenderTask = false;
-
- if (typeof renderTask === "undefined") {
- useFirstRenderTask = true;
- } else if (renderTask === null) { // null is an object
- useFirstRenderTask = true;
- }
-
- if (useFirstRenderTask) {
- var tasks = dali.stage.getRenderTaskList();
- renderTask = tasks.getTask(0);
- tasks.delete(); // wrapper
- }
-
- var camera = renderTask.getCameraActor();
- var pos = renderTask.getCurrentViewportPosition();
- var size = renderTask.getCurrentViewportSize();
-
- var mat = dali.matrixByMatrix(camera.viewMatrix, camera.projectionMatrix);
- var p = dali.matrixByVector(mat, position);
- var depthRange = [0, 1];
- var viewport = [pos[0], pos[1], size[0], size[1]];
-
- var div;
- // homogenous divide
- if(0.0 === p[3]) {
- div = 1.0;
- } else {
- div = 1 / p[3];
- }
-
- camera.delete(); // wrapper
-
- return [
- (1 + p[0] * div) * viewport[2] / 2 + viewport[0], (1 - p[1] * div) * viewport[3] / 2 + viewport[1], (p[2] * div) * (depthRange[1] - depthRange[0]) + depthRange[0],
- div
- ];
-};
-
-/**
- * Gets matrix identity
- * @method matrixIdentity
- * @return {array} Matrix4 identity
- */
-dali.matrixIdentity = function() {
- "use strict";
- return [1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- ];
-};
-
-/**
- * Gets matrix identity with position transformation
- * @method matrixTransform
- * @param {float} x X position
- * @param {float} y Y position
- * @param {float} z Z position
- * @return {array} Matrix4
- */
-dali.matrixTransform = function(x, y, z) {
- "use strict";
- return [1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- x, y, z, 1
- ];
-};
-
-/**
- * Gets matrix identity with position transformation
- * @method screenToPlaneLocal
- * @param {float} screenX Screen X position
- * @param {float} screenY Screen Y position
- * @param {Dali.RenderTask} Dali RenderTask
- * @param {array} planeOrientationMatrix
- * @param {float} planeWidth
- * @param {float} planeHeight
- * @return {array} Local coordinates
- */
-dali.screenToPlaneLocal = function(screenX, screenY, renderTask, planeOrientationMatrix, planeWidth, planeHeight) {
- "use strict";
-
- var camera = renderTask.getCameraActor();
-
- var pos = renderTask.getCurrentViewportPosition();
- var size = renderTask.getCurrentViewportSize();
- var viewportX = pos[0];
- var viewportY = pos[1];
- var viewportW = size[0];
- var viewportH = size[1];
- var modelView = dali.matrixByMatrix(planeOrientationMatrix, camera.viewMatrix);
-
- var inverseMvp = dali.matrixInverse(
- dali.matrixByMatrix(modelView, camera.projectionMatrix));
-
- var screenPos = [screenX - viewportX,
- viewportH - (screenY - viewportY),
- 0.0, 1.0
- ];
-
- screenPos[2] = 0.0;
-
- var oglScreenPos = [(screenPos[0] / viewportW) * 2 - 1, (screenPos[1] / viewportH) * 2 - 1, (screenPos[2]) * 2 - 1,
- 1
- ];
-
-
- var nearPoint = dali.matrixByVector(inverseMvp, oglScreenPos);
-
- if (nearPoint[3] === 0.0) {
- throw "Unproject near fails";
- }
-
- nearPoint[3] = 1 / nearPoint[3];
- nearPoint[0] = nearPoint[0] * nearPoint[3];
- nearPoint[1] = nearPoint[1] * nearPoint[3];
- nearPoint[2] = nearPoint[2] * nearPoint[3];
-
-
- oglScreenPos[2] = 1.0 * 2 - 1;
-
- var farPoint = dali.matrixByVector(inverseMvp, oglScreenPos);
-
- if (farPoint[3] === 0.0) {
- throw "Unproject far fails";
- }
-
- farPoint[3] = 1 / farPoint[3];
- farPoint[0] = farPoint[0] * farPoint[3];
- farPoint[1] = farPoint[1] * farPoint[3];
- farPoint[2] = farPoint[2] * farPoint[3];
-
- if (!((farPoint[2] < 0) && (nearPoint[2] > 0))) {
- throw "ray not crossing xy plane";
- }
-
- var dist = nearPoint[2] / (nearPoint[2] - farPoint[2]);
-
- var intersect = [nearPoint[0] + (farPoint[0] - nearPoint[0]) * dist,
- nearPoint[1] + (farPoint[1] - nearPoint[1]) * dist,
- 0.0
- ];
-
- intersect[0] = intersect[0] + planeWidth * 0.5;
- intersect[1] = intersect[1] + planeHeight * 0.5;
-
- return intersect;
-};
-
-/**
- * Gets matrix identity with position transformation
- * @method screenToLocal
- * @param {float} screenX Screen X position
- * @param {float} screenY Screen Y position
- * @param {Dali.Actor} actor Dali Actor
- * @param {Dali.RenderTask} renderTask Dali RenderTask
- * @return {array} Local coordinates
- */
-dali.screenToLocal = function(screenX, screenY, actor, renderTask) {
- "use strict";
- return dali.screenToPlaneLocal(screenX, screenY, renderTask, actor.worldMatrix, actor.size[0], actor.size[1]);
-};
-
-/**
- * Screen to local coordinates in the XY plane
- * @method screenToXY
- * @param {float} screenX Screen X position
- * @param {float} screenY Screen Y position
- * @param {Dali.Actor} actor Dali Actor
- * @param {Dali.RenderTask} renderTask Dali RenderTask
- * @return {array} Local coordinates
- */
-dali.screenToXY = function(screenX, screenY, actor, renderTask) {
- "use strict";
- var size = dali.stage.getSize();
- return dali.screenToPlaneLocal(screenX, screenY,
- renderTask,
- dali.matrixIdentity(),
- size[0],
- size[1]);
-};
-
-/**
- * Screen to local coordinates in the YZ plane
- * @method screenToYZ
- * @param {float} screenX Screen X position
- * @param {float} screenY Screen Y position
- * @param {Dali.Actor} actor Dali Actor
- * @param {Dali.RenderTask} renderTask Dali RenderTask
- * @return {array} Local coordinates
- */
-dali.screenToYZ = function(screenX, screenY, actor, renderTask) {
- "use strict";
- var size = dali.stage.getSize();
- var q = dali.axisAngleToQuaternion( [0, 1, 0, dali.radian(90)] );
- return dali.screenToPlaneLocal(screenX, screenY,
- renderTask,
- dali.quaternionToMatrix(q),
- size[0],
- size[1]);
-};
-
-/**
- * Screen to local coordinates in the XZ plane
- * @method screenToXZ
- * @param {float} screenX Screen X position
- * @param {float} screenY Screen Y position
- * @param {Dali.Actor} actor Dali Actor
- * @param {Dali.RenderTask} renderTask Dali RenderTask
- * @return {array} Local coordinates
- */
-dali.screenToXZ = function(screenX, screenY, actor, renderTask) {
- "use strict";
- var size = dali.stage.getSize();
- var q = dali.axisAngleToQuaternion( [1, 0, 0, dali.radian(90)] );
- return dali.screenToPlaneLocal(screenX, screenY,
- renderTask,
- dali.quaternionToMatrix(q),
- size[0],
- size[1]);
-};
-
-/**
- * Screen coordinates for the given renderTask
- * @method screenCoordinates
- * @param {Dali.Actor} actor Dali Actor
- * @param {Dali.RenderTask} renderTask Dali RenderTask
- * @return {array} Local coordinates
- */
-dali.screenCoordinates = function(actor, renderTask) {
- "use strict";
- var size = actor.size;
- var w2 = size[0] / 2;
- var h2 = size[1] / 2;
- var actorWorldMatrix = actor.worldMatrix;
- var actorWorldPosition = actor.worldPosition;
-
- return {
- topLeft: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [-w2, -h2, 0]), renderTask),
- topRight: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [+w2, -h2, 0]), renderTask),
- bottomRight: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [+w2, +h2, 0]), renderTask),
- bottomLeft: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [-w2, +h2, 0]), renderTask),
- centre: dali.worldToScreen(actorWorldPosition, renderTask)
- };
-};
-
-/**
- * Screen coordinates for the given renderTask
- * @method screenCoordinates
- * @param {Dali.Actor} actor Dali Actor
- * @param {Dali.RenderTask} renderTask Dali RenderTask
- * @return {array} Local coordinates
- */
-dali.screenToActor = function(actor, screenPos, renderTask) {
- "use strict";
- // , function will return coordinates in relation to actor`s anchorPoint (client coordinates).
- var useFirstRenderTask = false;
-
- if (typeof renderTask === "undefined") {
- useFirstRenderTask = true;
- } else if (renderTask === null) { // null is an object
- useFirstRenderTask = true;
- }
-
- if (useFirstRenderTask) {
- var tasks = dali.stage.getRenderTaskList();
- renderTask = tasks.getTask(0);
- tasks.delete(); // wrapper
- }
-
- var camera = renderTask.getCameraActor();
- var vpp = renderTask.getCurrentViewportPosition();
- var vps = renderTask.getCurrentViewportSize();
-
- var mat = dali.matrixByMatrix(camera.projectionMatrix, camera.viewMatrix);
-
- var inverseMvp = dali.matrixInverse(mat);
-
- var x = screenPos[0];
- var y = screenPos[1];
- var z = screenPos[2];
-
- var objectPos = dali.matrixByVector(inverseMvp,
- // normalized +-1
- [((x - vpp[0]) / vps[0]) * 2.0 - 1.0, ((y - vpp[1]) / vps[1]) * 2.0 - 1.0, (z * 2.0) - 1.0,
- 1.0
- ]);
-
- if (objectPos[3] === 0.0) {
- throw "Cannot find screen Position";
- }
-
- objectPos[3] = 1 / objectPos[3];
-
- return [objectPos[0] * objectPos[3],
- objectPos[1] * objectPos[3],
- objectPos[2] * objectPos[3],
- objectPos[3]
- ];
-};
-
-
-//------------------------------------------------------------------------------
-//
-// Utils Module
-//
-//------------------------------------------------------------------------------
-
-/**
- * Cache to fix the dali get/set thread issue
- *
- * Property sets are cached and cleared at the renderFinished callback
- */
-dali.internalUniqueId = function() {
- "use strict";
-};
-
-dali.internalUniqueId.prototype._id = 0;
-dali.internalUniqueId.prototype.generateId = function() {
- "use strict";
- return ++dali.internalUniqueId.prototype._id;
-};
-
-dali.internalPropertyCacheEnable = true;
-dali.internalPropertyCache = {};
-
-/**
- * Merge two objects together in a simplistic key,value merge
- * @method mergeObjects
- * @param {object} o1 first object
- * @param {object} o2 second object
- * @return {object} The merged objects
- */
-dali.mergeObjects = function(o1, o2) {
- "use strict";
- for (var p in o2) {
- try {
- // Property in destination object set; update its value.
- if ( o2[p].constructor === Object){
- o1[p] = dali.mergeObjects(o1[p], o2[p]);
-
- } else {
- o1[p] = o2[p];
- }
- } catch(e) {
- // Property in destination object not set; create it and set its value.
- o1[p] = o2[p];
- }
- }
- return o1;
-};
-
-//------------------------------------------------------------------------------
-//
-// Callbacks Module
-//
-// Data dali can request during update & render loop.
-//
-//------------------------------------------------------------------------------
-
-/**
- * Gets a glyph by rendering to a hidden browser canvas
- */
-/** @private */
-dali.requestedGlyphImage = function(sFontFamily, sFontStyle, fFontSize, iChar) {
- "use strict";
-
- var buffer = document.createElement("canvas");
- buffer.width = fFontSize;
- buffer.height = fFontSize;
- var ctx = buffer.getContext("2d");
-
- ctx.font = sFontStyle + " " + fFontSize + "px " + sFontFamily;
- ctx.fillText(String.fromCharCode(iChar), 0, 0 + fFontSize);
-
- var imageData = ctx.getImageData(0, 0, fFontSize, fFontSize);
-
- // emscripten checks only for this type if array in converting to strings
- // (getImageData() returns Uint8CheckedArray or some such)
- // var uint8array = new Uint8Array( imageData.data );
-
- return imageData.data; // return uint8array; //
-};
-
-/** @private */
-dali.postRenderFunction = undefined;
-
-/*
- * End of renderering tasks
- * - Reset the property cache
- */
-/** @private */
-dali.requestedRenderFinished = function() {
- "use strict";
- // reset the temporary cache
- dali.internalPropertyCache = {};
- if(dali.postRenderFunction) {
- dali.postRenderFunction();
- }
-};
-
-dali.setCallbackGetGlyphImage(dali.requestedGlyphImage);
-dali.setCallbackRenderFinished(dali.requestedRenderFinished);
-
-//------------------------------------------------------------------------------
-//
-// Property Marshalling Module
-//
-// Javascript objects are adorned with dali properties as they are created or
-// fetched from the C++ api
-//
-// Data is marshalled to avoid some of the necessary C++ memory management for
-// small property classes.
-//
-//------------------------------------------------------------------------------
-dali.__propertyTypeJsLut = { boolean: dali.PropertyType.BOOLEAN,
- number: dali.PropertyType.FLOAT,
- string: dali.PropertyType.STRING };
-
-dali.__propertyValueCtor = {};
-
-[ [dali.PropertyType.INTEGER.value, dali.PropertyValueInteger],
- [dali.PropertyType.FLOAT.value, dali.PropertyValueFloat],
- [dali.PropertyType.STRING.value, dali.PropertyValueString],
- [dali.PropertyType.VECTOR2.value, dali.PropertyValueVector2],
- [dali.PropertyType.VECTOR3.value, dali.PropertyValueVector3],
- [dali.PropertyType.VECTOR4.value, dali.PropertyValueVector4],
- [dali.PropertyType.MATRIX.value, dali.PropertyValueMatrix],
- [dali.PropertyType.MATRIX3.value, dali.PropertyValueMatrix3],
- [dali.PropertyType.ARRAY.value, dali.PropertyValueArray],
- [dali.PropertyType.MAP.value, dali.PropertyValueMap],
- [dali.PropertyType.RECTANGLE.value, dali.PropertyValueIntRect] ].map( function(ab) { dali.__propertyValueCtor[ ab[0] ] = ab[1]; } );
-
-dali.propertyTypeFromJsValue = function(value) {
- return dali.__propertyTypeJsLut[ typeof(value) ];
-};
-
-dali.propertyValueCtor = function(propertyType) {
- return dali.__propertyValueCtor[ propertyType.value ];
-};
-
-/**
- * Create a Dali PropertyValue from a javascript value.
- * @method DaliPropertyValue
- * @param {object} object to retrieve the property type when value is an object
- * @param {string} name The name of the property
- * @return {Dali.PropertyValue} A Dali PropertyValue which must be '.delete()' when finished with
- */
-dali.DaliPropertyValue = function(object, name, value) {
- "use strict";
-
- var setProperty = false;
- if (typeof (value) === "boolean") {
- setProperty = new dali.PropertyValueBoolean(value);
- } else if (typeof (value) === "number") {
- setProperty = new dali.PropertyValueFloat(value);
- } else if (typeof (value) === "string") {
- setProperty = new dali.PropertyValueString(value);
- } else if (typeof (value) === "object") {
- if (value.constructor === dali.PropertyValueValue) {
- setProperty = value;
- } else {
- var type = false;
- if (object) {
- type = object.getPropertyTypeFromName(name);
- }
- if (type === dali.PropertyType.ROTATION) {
- if (value.length === 3) {
- setProperty = new dali.PropertyValueEuler(value);
- } else {
- setProperty = new dali.PropertyValueAxisAngle(value);
- }
- } else if (value.length) {
- if (type === dali.PropertyType.ARRAY) {
- setProperty = new dali.PropertyValueArray(value);
- } else {
- if (value.length === 2) {
- setProperty = new dali.PropertyValueVector2(value);
- } else if (value.length === 3) {
- setProperty = new dali.PropertyValueVector3(value);
- } else if (value.length === 4) {
- if (type === dali.PropertyType.RECTANGLE) {
- setProperty = new dali.PropertyValueIntRect(value[0], value[1], value[2], value[3]);
- } else {
- setProperty = new dali.PropertyValueVector4(value);
- }
- } else if (value.length === 9) {
- setProperty = new dali.PropertyValueMatrix3(value);
- } else if (value.length === 16) {
- setProperty = new dali.PropertyValueMatrix(value);
- } else {
- throw new Error("Cannot set property");
- }
- }
- } else {
- // todo; I think a map has a length....
- setProperty = new dali.PropertyValueMap(value);
- }
- }
- } else {
- if (object) {
- throw object.toString() + " " + name.toString() + " " + value.toString();
- } else {
- throw name.toString() + " " + value.toString();
- }
- }
-
- return setProperty;
-};
-
-/**
- * Get the value type held in a PropertyValue and call '.delete()' to drop the C++ backing object
- * @method marshallProperty
- * @param {Dali.PropertyValue} p A Dali PropertyValue. This will be '.delete()'ed.
- * @return {any} The value held
- */
-/** @private */
-dali.marshallProperty = function(p) {
- "use strict";
-
- var ret;
- var type = p.getType();
-
- if (type === 0) {
- // raise?
- throw new Error("Property has no type?");
- } else if (type === dali.PropertyType.BOOLEAN.value) {
- ret = p.getBoolean();
- } else if (type === dali.PropertyType.FLOAT.value) {
- ret = p.getFloat();
- } else if (type === dali.PropertyType.INTEGER.value) {
- ret = p.getInteger();
- } else if (type === dali.PropertyType.VECTOR2.value) {
- ret = p.getVector2();
- } else if (type === dali.PropertyType.VECTOR3.value) {
- ret = p.getVector3();
- } else if (type === dali.PropertyType.VECTOR4.value) {
- ret = p.getVector4();
- } else if (type === dali.PropertyType.MATRIX3.value) {
- ret = p.getMatrix3();
- } else if (type === dali.PropertyType.MATRIX.value) {
- ret = p.getMatrix();
- } else if( type === dali.PropertyType.RECTANGLE ) {
- ret = p.getIntRect();
- } else if (type === dali.PropertyType.ROTATION.value) {
- ret = p.getRotation();
- } else if (type === dali.PropertyType.STRING.value) {
- ret = p.getString();
- } else if (type === dali.PropertyType.ARRAY.value) {
- ret = p.getArray();
- } else if (type === dali.PropertyType.MAP.value) {
- ret = p.getMap();
- }
- p.delete();
- return ret;
-};
-
-/**
- * Set a value on an object by creating and deleting a Dali PropertyValue object
- * @method marshallSetProperty
- * @param {object} object The object who's property to set from
- * @param {string} name The property name
- * @param {any} value The Javascript value
- */
-/** @private */
-dali.marshallSetProperty = function(object, name, value) {
- "use strict";
- var setProperty = new dali.DaliPropertyValue(object, name, value);
-
- if (setProperty) {
-
- object.setProperty(name, setProperty);
-
- //console.log("marshallSetProperty set property" + setProperty );
- setProperty.delete();
-
- if(dali.internalPropertyCacheEnable) {
- // set in cache to fix dali get/set problem
- if("getId" in object ) // only with actors
- {
- var uniqueId = object.getId(); // _uniqueId;
- if (uniqueId !== undefined) {
- var objectDict = dali.internalPropertyCache[uniqueId];
- if (objectDict === undefined) {
- dali.internalPropertyCache[uniqueId] = {};
- }
- dali.internalPropertyCache[uniqueId][name] = value;
- }
- }
- }
- }
-};
-
-/**
- * Get a Javascript value from an object by creating and deleting a PropertyValue
- * @method marshallGetProperty
- * @param {object} object The object who's property to get from
- * @param {string} name The property name
- * @return {any} The value of the property
- */
-/** @private */
-dali.marshallGetProperty = function(object, name) {
- "use strict";
-
- if(dali.internalPropertyCacheEnable) {
- // is the value live in the cache? if so use that value instead
- if("getId" in object) { // only with actors
- var uniqueId = object.getId(); // _uniqueId;
- if (uniqueId !== undefined) {
- var objectDict = dali.internalPropertyCache[uniqueId];
- if (objectDict !== undefined) {
- var value = dali.internalPropertyCache[uniqueId][name];
- if (value !== undefined) {
- return value;
- }
- }
- }
- }
- }
-
- var ret;
- var p;
- p = object.getProperty(name);
- if (!p) {
- throw new Error("Property doesnt exist?");
- }
- var type = p.getType();
-
- if (type === 0) {
- // raise?
- throw new Error("Property has no type?");
- } else if (type === dali.PropertyType.BOOLEAN.value) {
- ret = p.getBoolean();
- } else if (type === dali.PropertyType.FLOAT.value) {
- ret = p.getFloat();
- } else if (type === dali.PropertyType.INTEGER.value) {
- ret = p.getInteger();
- } else if (type === dali.PropertyType.VECTOR2.value) {
- ret = p.getVector2();
- } else if (type === dali.PropertyType.VECTOR3.value) {
- ret = p.getVector3();
- } else if (type === dali.PropertyType.VECTOR4.value) {
- // VECTOR4
- ret = p.getVector4();
- } else if (type === dali.PropertyType.MATRIX3.value) {
- // MATRIX3
- ret = p.getMatrix3();
- } else if (type === dali.PropertyType.MATRIX.value) {
- // MATRIX
- ret = p.getMatrix();
- } else if( type === dali.PropertyType.RECTANGLE ) {
- ret = p.getIntRect();
- } else if (type === dali.PropertyType.ROTATION.value) {
- ret = p.getRotation();
- } else if (type === dali.PropertyType.STRING.value) {
- ret = p.getString();
- } else if (type === dali.PropertyType.ARRAY.value) {
- ret = p.getArray();
- } else if (type === dali.PropertyType.MAP.value) {
- ret = p.getMap();
- }
- p.delete();
- return ret;
-};
-
-
-/**
- * Set property accessors on the given handle for each property found on the handle
- * @method internalSetupProperties
- * @param {Dali.BaseHandle} handle A Dali property holding object
- * @return {Dali.BaseHandle} The same handle which has property accessors.
- */
-/** @private */
-dali.internalSetupProperties = function(handle) {
- "use strict";
- if(handle.ok()) {
- var props = handle.getProperties();
-
- for (var i = 0; i < props.size(); i++) {
- // anon function because of closure with defineProperty
- // (if just variable in loop then the variable 'address' is captured, not the value
- // so it becomes last value set)
- (function(name, object) {
- // @todo Dali error?? name lengths should never be zero
- if (name.length) {
- Object.defineProperty(handle, name, {
- enumerable: true,
- configurable: false,
- get: function() {
- return dali.marshallGetProperty(handle, name);
- },
- set: function(newValue) {
- dali.marshallSetProperty(handle, name, newValue);
- }
- });
- }
- })(props.get(i), handle);
- }
-
- // handle._uniqueId = dali.internalUniqueId.prototype.generateId();
- }
-
- return handle;
-};
-
-//------------------------------------------------------------------------------
-//
-// Handle API Module
-//
-// API Wrappers for some Dali.Handle methods to marshall properties
-//
-//------------------------------------------------------------------------------
-
-/**
- * Register a new property and add JS style property accessors
- * @method registerProperty
- * @param {string} name The property name
- * @param {any} value Any Javascript value
- * @return {int} The registered properties ID
- */
-dali.Handle.prototype.registerProperty = function(name, value) {
- "use strict";
- var ret = -1;
-
- var propertyValue = new dali.DaliPropertyValue(null, name, value);
- ret = this.__registerProperty(name, propertyValue);
- propertyValue.delete(); // wrapper
- Object.defineProperty(this, name, {
- enumerable: true,
- configurable: false,
- get: function() {
- return dali.marshallGetProperty(this, name);
- },
- set: function(newValue) {
- dali.marshallSetProperty(this, name, newValue);
- }
- });
-
- return ret;
-};
-
-/**
- * Register a new animated property
- * @method registerAnimatedProperty
- * @param {string} name The property name
- * @param {any} value Any Javascript value
- * @return {int} The registered properties ID
- */
-dali.Handle.prototype.registerAnimatedProperty = function(name, value) {
- "use strict";
- var ret = -1;
-
- var propertyValue = new dali.DaliPropertyValue(null, name, value);
- ret = this.__registerAnimatedProperty(name, propertyValue);
- propertyValue.delete(); // wrapper
- Object.defineProperty(this, name, {
- enumerable: true,
- configurable: false,
- get: function() {
- return dali.marshallGetProperty(this, name);
- },
- set: function(newValue) {
- dali.marshallSetProperty(this, name, newValue);
- }
- });
- return ret;
-};
-
-//------------------------------------------------------------------------------
-//
-// Stage Module
-//
-//------------------------------------------------------------------------------
-dali.Stage.prototype.getRootLayer = function() {
- "use strict";
- var root = this.__getRootLayer();
- dali.internalSetupProperties(root);
- return root;
-};
-
-//------------------------------------------------------------------------------
-//
-// PropertyMap Module
-//
-// API Wrappers for some Dali.PropertyMap methods to marshall properties
-//
-//------------------------------------------------------------------------------
-
-/**
- * Insert a value into the PropertyMap
- * @method insert
- * @param {string} key The key
- * @param {any} value Any Javascript value
- * @param {PropertyType} propertyType The Dali property type
- */
-dali.PropertyMap.prototype.insert = function(key, value, propertyType) {
- "use strict";
-
- var type = propertyType;
-
- if( propertyType === undefined ) { // can be optional
- propertyType = dali.propertyTypeFromJsValue(value);
- }
-
- var constructor = dali.propertyValueCtor(propertyType);
-
- var setProperty = constructor( value );
-
- if(setProperty) {
- this.__insert(key, setProperty);
- setProperty.delete();
- }
-};
-
-/**
- * Get a value from the PropertyMap
- * @method get
- * @param {string} key The key
- * @return The Javascript value
- */
-dali.PropertyMap.prototype.get = function(key) {
- "use strict";
- var p = this.__get(key);
-
- var ret = dali.marshallProperty(p);
-
- // p.delete(); // @todo should we delete here?
-
- return ret;
-};
-
-//------------------------------------------------------------------------------
-//
-// PropertyBuffer Module
-//
-// API Wrappers for some Dali.PropertyBuffer methods to marshall properties
-//
-//------------------------------------------------------------------------------
-var _propertyTypeInfoList = [
- [ dali.PropertyType.FLOAT.value, { size: 4, length: 1, dataView: Float32Array }],
- [ dali.PropertyType.INTEGER.value, { size: 4, length: 1, dataView: Int32Array }],
- [ dali.PropertyType.VECTOR2.value, { size: 2 * 4, length: 2, dataView: Float32Array }],
- [ dali.PropertyType.VECTOR3.value, { size: 3 * 4, length: 3, dataView: Float32Array }],
- [ dali.PropertyType.VECTOR4.value, { size: 4 * 4, length: 4, dataView: Float32Array }],
- [ dali.PropertyType.MATRIX3.value, { size: 9 * 4, length: 9, dataView: Float32Array }],
- [ dali.PropertyType.MATRIX.value, { size: 16 * 4, length: 16, dataView: Float32Array }]
-];
-
-var _propertyTypeInfo = {};
-function _createPropertyBuffer() {
- "use strict";
- for(var i = 0; i < _propertyTypeInfoList.length; i++) {
- _propertyTypeInfo[ _propertyTypeInfoList[i][0] ] = _propertyTypeInfoList[i][1];
- }
-}
-
-_createPropertyBuffer();
-
-/**
- * Create a Dali.PropertyBuffer from an info dictionary
- * @method createPropertyBuffer
- * @param {object} info
- * @param {any} value Any Javascript value
- * @param {PropertyType} propertyType The Dali property type
- * @example
- * var verts = createPropertyBuffer( {format: [ ["apos", dali.PropertyType.VECTOR2],
- * ["acol", dali.PropertyType.VECTOR4] ],
- * data: { "apos": [ [-halfQuadSize, -halfQuadSize],
- * [+halfQuadSize, -halfQuadSize],
- * [-halfQuadSize, +halfQuadSize],
- * [+halfQuadSize, +halfQuadSize]
- * ],
- * "acol": [ [0, 0, 0, 1],
- * [1, 0, 1, 1],
- * [0, 1, 0, 1],
- * [1, 1, 1, 1]
- * ]
- * }
- * }
- */
-dali.createPropertyBuffer = function(info) {
- "use strict";
- var format = new dali.PropertyMap();
- var dataLength;
- var recordSize = 0;
- var i;
- for(i = 0; i < info.format.length; i++) {
- format.insert(info.format[i][0], info.format[i][1].value, dali.PropertyType.INTEGER);
- if(dataLength === undefined) {
- dataLength = info.data[info.format[i][0]].length;
- }
- assert(info.data[info.format[i][0]]);
- assert(dataLength === info.data[info.format[i][0]].length);
- recordSize += _propertyTypeInfo[info.format[i][1].value].size;
- }
-
- var buffer = new ArrayBuffer(dataLength * recordSize);
-
- var recordOffset = 0;
- var offset = 0;
- for(i = 0; i < dataLength; i++) {
- for(var j = 0; j < info.format.length; j++) {
- var name = info.format[j][0];
- var type = info.format[j][1].value;
- var length = _propertyTypeInfo[type].length;
- var DataView = _propertyTypeInfo[type].dataView;
- var view = new DataView(buffer, recordOffset + offset, length);
- offset += _propertyTypeInfo[type].size;
- if(length === 1) {
- view[0] = info.data[name][i];
- } else {
- for(var k = 0; k < length; k++) {
- view[k] = info.data[name][i][k];
- }
- }
- }
- offset = 0;
- recordOffset += recordSize;
- }
-
- var propertyBuffer = new dali.PropertyBuffer(format);
-
- propertyBuffer.setData(buffer, dataLength);
-
- format.delete(); //
-
- return propertyBuffer;
-};
-
-//------------------------------------------------------------------------------
-//
-// Actor Module
-//
-// API Wrappers for some Dali.PropertyBuffer methods to marshall properties
-//
-//------------------------------------------------------------------------------
-
-/**
- * Gets a parent with JS style property accessors
- * @method getParent
- * @return The parent
- */
-dali.Actor.prototype.getParent = function() {
- "use strict";
- var bareActor = this.__getParent();
- if(!bareActor.ok()) {
- bareActor.delete(); // wrapper
- bareActor = null;
- } else {
- // add properties to the bare Actor
- dali.internalSetupProperties(bareActor);
- }
- return bareActor;
-};
-
-/**
- * Finds child by ID and adorns with JS style property accessors
- * @method findChildById
- * @param {int} index The ID of the child
- * @return The found child or null
- */
-dali.Actor.prototype.findChildById = function(index) {
- "use strict";
- var bareActor = this.__findChildById(index);
- if(!bareActor.ok()) {
- bareActor.delete(); // wrapper
- bareActor = null;
- } else {
- dali.internalSetupProperties(bareActor);
- }
- return bareActor;
-};
-
-/**
- * Finds child by name and adorns with JS style property accessors
- * @method findChildByName
- * @param {string} name The ID of the child
- * @return The found child or null
- */
-dali.Actor.prototype.findChildByName = function(name) {
- "use strict";
- var bareActor = this.__findChildByName(name);
- if(!bareActor.ok()) {
- bareActor.delete(); // wrapper
- bareActor = null;
- } else {
- dali.internalSetupProperties(bareActor);
- }
- return bareActor;
-};
-
-/**
- * Gets child at child index and adorns with JS style property accessors
- * @method getChildAt
- * @param {int} index The ID of the child
- * @return The found child or null
- */
-dali.Actor.prototype.getChildAt = function(index) {
- "use strict";
- var bareActor = this.__getChildAt(index);
- if(!bareActor.ok()) {
- bareActor.delete(); // wrapper
- bareActor = null;
- } else {
- dali.internalSetupProperties(bareActor);
- }
- return bareActor;
-};
-
-/*
- * add children of actor to collection in depth first manner
- */
-/** @private */
-dali.internalDepthFirstCollection = function(actor, collection) {
- "use strict";
- for (var i = 0; i < actor.getChildCount(); i++) {
- var a = actor.getChildAt(i); // adds properties in dotted
- collection.push(a);
- dali.internalDepthFirstCollection(a, collection);
- }
-};
-
-/**
- * Finds all children of the actor and adorns with JS style property accessors
- * @method findAllChildren
- * @return A list of children
- */
-dali.Actor.prototype.findAllChildren = function() {
- "use strict";
- var col = [];
- dali.internalDepthFirstCollection(this, col);
- return col;
-};
-
-/**
- * Gets a childFinds all children of the actor and adorns with JS style property accessors
- * @method getChildren
- * @return A list of children
- */
-dali.Actor.prototype.getChildren = function() {
- "use strict";
- var col = [];
- for (var i = 0, len = this.getChildCount(); i < len; i++) {
- var c = this.getChildAt(i);
- col.push(c);
- }
- return col;
-};
-
-/**
- * 'directChildren' kept for GUIBuilder support
- * @deprecated
- */
-dali.Actor.prototype.directChildren = dali.Actor.prototype.getChildren;
-
-/**
- * Connects a callback to a signal by name
- * @method connect
- * @param {string} signalName The signal to connect to
- * @param {function} callback The callback to call
- * @param {Dali.SignalHolder} The signal holder object that can signal connection deletion
- * @return true if connection was possible
- */
-dali.Actor.prototype.connect = function(signalName, callback, signalHolder) {
- "use strict";
- // wrap in closure so we can setup properties in . notation
- // and add actor methods to c++ raw Actor
- if(signalHolder === undefined) {
- // default js signal holder if none provided
- signalHolder = dali.jsSignalHolder;
- }
-
- return this.__connect( signalHolder,
- signalName,
- (function(cb) {
- return function() {
- var args = [dali.internalSetupProperties(arguments[0])];
- for(var i = 1; i < arguments.length; i++) {
- args.push( arguments[i] );
- }
- cb.apply(null, args);
- };
- })(callback)
- );
-};
-
-/**
- * Connects a callback to a property notification
- * @method setPropertyNotification
- * @param {string} property The property name
- * @param {string} condition The condition [False,LessTHan,GreaterThan,Inside,Outside,Step,VariableStep]
- * @param {any} arg0 The first property notification argument
- * @param {any} arg1 The second property notification argument
- * @param {function} callback The callback function
- * @param {Dali.SignalHolder} The signal holder object that can signal connection deletion
- * @return true if connection was possible
- */
-dali.Actor.prototype.setPropertyNotification = function(property, condition, arg0, arg1, callback, signalHolder) {
- "use strict";
-
- if(signalHolder === undefined) {
- // default js signal holder if none provided
- signalHolder = dali.jsSignalHolder;
- }
-
- var index = this.getPropertyIndex(property);
-
- this.__setPropertyNotification(signalHolder, index, condition, arg0, arg1, callback);
-};
-
-/**
- * Gets the renderer by index
- * @method getRendererAt
- * @param {int} index The index of the renderer
- * @return The Render or null
- */
-dali.Actor.prototype.getRendererAt = function(index) {
- "use strict";
- var renderer = this.__getRendererAt(index);
- if(!renderer.ok()) {
- renderer.delete(); // wrapper
- renderer = null;
- } else {
- dali.internalSetupProperties(renderer);
- }
- return renderer;
-};
-
-/** private */
-dali.__ActorConstructor = dali.Actor;
-
-/**
- * Construtor that adorns with JS style property accessors
- * @return The wrapped Dali.Actor object
- */
-dali.Actor = function() {
- "use strict";
- var a = new dali.__ActorConstructor();
- dali.internalSetupProperties(a);
- return a;
-};
-
-//------------------------------------------------------------------------------
-//
-// New Mesh Module
-//
-//------------------------------------------------------------------------------
-dali.__ShaderConstructor = dali.Shader;
-dali.Shader = function(vertex, fragment, hints) {
- "use strict";
- var a = new dali.__ShaderConstructor(vertex, fragment, hints);
- dali.internalSetupProperties(a);
- return a;
-};
-
-dali.__MaterialConstructor = dali.Material;
-dali.Material = function(shader) {
- "use strict";
- var a = new dali.__MaterialConstructor(shader);
- dali.internalSetupProperties(a);
- return a;
-};
-
-dali.__RendererConstructor = dali.Renderer;
-dali.Renderer = function(geometry, material) {
- "use strict";
- var a = new dali.__RendererConstructor(geometry, material);
- dali.internalSetupProperties(a);
- return a;
-};
-
-//------------------------------------------------------------------------------
-//
-// Animation Module
-//
-//------------------------------------------------------------------------------
-dali.__PathConstructor = dali.Path;
-dali.Path = function() {
- "use strict";
- var a = new dali.__PathConstructor();
- dali.internalSetupProperties(a);
- return a;
-};
-
-/**
- * animateTo a value
- * @method animateTo
- * @param {object} The object
- * @param {string} propertyName The objects property name
- * @param {any} value The value
- * @param {string} alphaFunction The alpha function
- * @param {float} delay The delay
- * @param {float} duration The duration
- */
-dali.Animation.prototype.animateTo = function(object, propertyName, value, alphaFunction, delay, duration) {
- "use strict";
- var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
- if (propertyValue) {
- this.__animateTo(object, propertyName, propertyValue, alphaFunction, delay, duration);
- propertyValue.delete();
- } else {
- throw new Error("Unknown property?");
- }
-};
-
-/**
- * animateBy a value
- * @method animateBy
- * @param {object} The object
- * @param {string} propertyName The objects property name
- * @param {any} value The value
- * @param {string} alphaFunction The alpha function
- * @param {float} delay The delay
- * @param {float} duration The duration
- */
-dali.Animation.prototype.animateBy = function(object, propertyName, value, alphaFunction, delay, duration) {
- "use strict";
- var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
- if (propertyValue) {
- this.__animateBy(object, propertyName, propertyValue, alphaFunction, delay, duration);
- propertyValue.delete();
- } else {
- throw new Error("Unknown property?");
- }
-};
-
-/**
- * Animate a Path
- * @method animatePath
- * @param {object} The object
- * @param {Dali.Path} pathObject The path object
- * @param {array} forward The path forward vector
- * @param {string} alphaFunction The alpha function
- * @param {float} delay The delay
- * @param {float} duration The duration
- */
-dali.Animation.prototype.animatePath = function(object, pathObject, forward, alphaFunction, delay, duration) {
- "use strict";
- this.__animatePath(object, pathObject, forward, alphaFunction, delay, duration);
-};
-
-/**
- * animateBetween a value
- * @method animateBetween
- * @param {object} The object
- * @param {string} propertyName The objects property name
- * @param {dali.KeyFrames} keyFrames The keyframes
- * @param {string} alphaFunction The alpha function
- * @param {float} delay The delay
- * @param {float} duration The duration
- */
-dali.Animation.prototype.animateBetween = function(object, propertyName, keyFrames, alphaFunction, delay, duration, interpolation) {
- "use strict";
- var propertyValue;
-
- var daliKeyFrames = new dali.KeyFrames();
-
- for(var i = 0; i < keyFrames.length; i++) {
- if(keyFrames[i].length > 2) { // has alpha
- propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
- if(!propertyValue) {
- throw new Error("Unknown property?");
- }
- daliKeyFrames.add(keyFrames[i][0], propertyValue, keyFrames[i][2]);
- propertyValue.delete();
- } else {
- propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
- if(!propertyValue) {
- throw new Error("Unknown property?");
- }
- daliKeyFrames.add(keyFrames[i][0], propertyValue);
- propertyValue.delete();
- }
- }
-
- this.__animateBetween(object, propertyName, daliKeyFrames, alphaFunction, delay, duration, interpolation);
-
- daliKeyFrames.delete();
-
-};
-
-//------------------------------------------------------------------------------
-//
-// RenderTask Module
-//
-//------------------------------------------------------------------------------
-dali.RenderTask.prototype.getCameraActor = function() {
- "use strict";
- var a = this.__getCameraActor();
- if (a.ok()) {
- dali.internalSetupProperties(a);
- }
- return a;
-};
-
-Object.defineProperty(dali.RenderTask.prototype, "x", {
- enumerable: true,
- configurable: false,
- get: function() {
- return this.getCurrentViewportPosition()[0];
- },
- set: function(v) {
- var pos = this.getCurrentViewportPosition();
- this.setViewportPosition(v, pos[1]);
- }
-});
-
-Object.defineProperty(dali.RenderTask.prototype, "y", {
- enumerable: true,
- configurable: false,
- get: function() {
- return this.getCurrentViewportPosition()[1];
- },
- set: function(v) {
- var pos = this.getCurrentViewportPosition();
- this.setViewportPosition(pos[0], v);
- }
-});
-
-Object.defineProperty(dali.RenderTask.prototype, "width", {
- enumerable: true,
- configurable: false,
- get: function() {
- return this.getCurrentViewportSize()[0];
- },
- set: function(v) {
- var pos = this.getCurrentViewportSize();
- this.setViewportSize(v, pos[1]);
- }
-});
-
-Object.defineProperty(dali.RenderTask.prototype, "height", {
- enumerable: true,
- configurable: false,
- get: function() {
- return this.getCurrentViewportSize()[1];
- },
- set: function(v) {
- var pos = this.getCurrentViewportSize();
- this.setViewportSize(pos[0], v);
- }
-});
-
-//------------------------------------------------------------------------------
-//
-// Solid Actor Module
-//
-//------------------------------------------------------------------------------
-
-/**
- * Create a solid color actor
- * @method createSolidColorActor
- * @param {array} color The color
- * @param {bool} border Whether to add a border
- * @param {array} color The border color
- * @param {float} borderSize The size of a border
- * @return {Dali.Actor} The Dali actor
- */
-dali.createSolidColorActor = function(color, border, borderColor, borderSize) {
- "use strict";
- var a = dali.__createSolidColorActor(color, border, borderColor, borderSize);
- dali.internalSetupProperties(a);
- return a;
-};
-
-//------------------------------------------------------------------------------
-//
-// Mesh import support Module
-//
-//------------------------------------------------------------------------------
-function ObjectLoader(fileObject) {
- "use strict";
- // cached
- this.self = this;
- this.meshByUUID = {};
- this.geomByUUID = {};
- this.matByUUID = {};
-
- this.fileObject = fileObject;
-}
-
-function __longToArray(v) {
- "use strict";
- return [((v >> 24) & 0xFF) / 255.0, ((v >> 16) & 0xFF) / 255.0, ((v >> 8) & 0xFF) / 255.0, (v & 0xFF) / 255.0];
-}
-
-function __isBitSet(value, bit) {
- "use strict";
- return (value & (1 << bit));
-}
-
-ObjectLoader.prototype.__getMaterial = function(uuid) {
- "use strict";
- if (!(uuid in this.matByUUID)) {
- for (var i = 0, len = this.fileObject.materials.length; i < len; i++) {
- var f_mat = this.fileObject["materials"][i];
- skewer.log(i + ":" + f_mat["uuid"] + " " + (f_mat["uuid"] === uuid));
- if (f_mat["uuid"] === uuid) {
- assert(f_mat["type"] === "MeshPhongMaterial");
- var mat = new dali.MaterialWrapper(uuid);
- mat.setDiffuseColor(__longToArray(f_mat["color"]));
- mat.setAmbientColor(__longToArray(f_mat["ambient"]));
- mat.setSpecularColor(__longToArray(f_mat["specular"]));
- mat.setEmissiveColor(__longToArray(f_mat["emmissive"]));
- mat.setShininess(f_mat["shininess"]);
- this.matByUUID[uuid] = mat;
- break;
- }
- }
- }
- return this.matByUUID[uuid];
-};
-
-ObjectLoader.prototype.__getMeshData = function(uuid, uuid_material) {
- "use strict";
- if (!(uuid in this.meshByUUID)) {
- for (var i = 0, len = this.fileObject["geometries"].length; i < len; i++) {
- var f_geom = this.fileObject["geometries"][i];
- if (f_geom["uuid"] === uuid) {
- var f_indices, // file data
- f_posns,
- f_norms,
- f_uvs,
- f_faces;
-
- if (!("metadata" in f_geom)) {
- f_geom["metadata"] = {
- "type": ""
- }; // Warning: modified input!?
- }
-
- if ("formatVersion" in f_geom["metadata"]) // then version 3.1
- {
- f_indices = f_geom["indices"];
- f_posns = f_geom["vertices"];
- f_norms = f_geom["normals"];
- f_uvs = f_geom["uvs"];
- f_faces = f_geom["faces"];
- } else if (f_geom["type"] === "Geometry") // V4 clara io output? not standard???
- {
- f_indices = f_geom["data"]["indices"];
- f_posns = f_geom["data"]["vertices"];
- f_norms = f_geom["data"]["normals"];
- f_uvs = f_geom["data"]["uvs"];
- f_faces = f_geom["data"]["faces"];
- } else if (f_geom["metadata"]["type"] === "Geometry") // V4
- {
- f_indices = f_geom["indices"];
- f_posns = f_geom["vertices"];
- f_norms = f_geom["normals"];
- f_uvs = f_geom["uvs"];
- f_faces = f_geom["faces"];
- } else if (f_geom["metadata"]["type"] === "BufferGeometry") // V4
- {
- f_posns = f_geom["data"]["attributes"]["position"]["array"];
- f_norms = f_geom["data"]["attributes"]["norms"]["array"];
- f_uvs = f_geom["data"]["attributes"]["uv"]["array"];
- }
-
- var nUvLayers = 0;
-
- // disregard empty arrays
- for (var i = 0; i < this.fileObject.uvs.length; i++) {
- if (this.fileObject.uvs[i].length)
- nUvLayers++;
- }
-
- var verts = new dali.VectorVertex();
- var vert = []; //new dali.Vertex();
- for (var i = 0, len = f_posns.length / 3; i < len; i++) {
- vert.push(f_posns[(i * 3) + 0]);
- vert.push(f_posns[(i * 3) + 1]);
- vert.push(f_posns[(i * 3) + 2]);
-
- vert.push(0); // norm
- vert.push(0);
- vert.push(0);
-
- vert.push(0); // uvs
- vert.push(0);
-
- verts.push_back(vert);
- }
-
- var mesh = new dali.MeshDataWrapper();
- var faces = new dali.VectorFaceIndex();
- var faceSets = {};
- //faceSets.length = this.fileObject.materials;
- for (var i = 0, len = this.fileObject.materials.length; i < len; ++i) {
- // get materials and force them to be loaded up
- var mat = this.__getMaterial(this.fileObject.materials[i]["uuid"]);
- }
-
- var idx = 0;
- var idx_len = f_faces.length;
- var materialUUID = undefined;
- while (idx < idx_len) {
- var f_type = f_faces[idx++];
- var isQuad = __isBitSet(f_type, 0);
- var hasMaterial = __isBitSet(f_type, 1);
- var hasFaceUv = __isBitSet(f_type, 2);
- var hasFaceVertexUv = __isBitSet(f_type, 3);
- var hasFaceNormal = __isBitSet(f_type, 4);
- var hasFaceVertexNormal = __isBitSet(f_type, 5);
- var hasFaceColor = __isBitSet(f_type, 6);
- var hasFaceVertexColor = __isBitSet(f_type, 7);
-
- var nVertices = 3;
- var faceVertexIndices;
- if (isQuad) {
- faces.push_back(f_faces[idx]);
- faces.push_back(f_faces[idx + 1]);
- faces.push_back(f_faces[idx + 2]);
-
- faces.push_back(f_faces[idx]);
- faces.push_back(f_faces[idx + 2]);
- faces.push_back(f_faces[idx + 3]);
-
- faceVertexIndices = [f_faces[idx],
- f_faces[idx + 1],
- f_faces[idx + 2]
- ];
-
- idx += 4;
- nVertices = 4;
- } else {
- faces.push_back(f_faces[idx]);
- faces.push_back(f_faces[idx + 1]);
- faces.push_back(f_faces[idx + 2]);
-
- faceVertexIndices = [f_faces[idx],
- f_faces[idx + 1],
- f_faces[idx + 2]
- ];
-
- idx += 3;
- }
-
- if (hasMaterial) {
- if (materialUUID === undefined) {
- materialUUID = this.fileObject.materials[f_faces[idx]]["uuid"];
- } else {
- // different material per face is bonkers - I'm not going to support it.
- if (this.fileObject.materials[f_faces[idx]]["uuid"] !== materialUUID) {
- throw "Faces with different materials is not supported";
- }
- }
- idx++;
- }
-
-
- if (hasFaceUv) {
- for (var i = 0; i < nUvLayers; i++) {
- var uvLayer = self.fileObject.uvs[i];
- var uvIndex = f_faces[idx++];
- var u = uvLayer[uvIndex * 2];
- var v = uvLayer[uvIndex * 2 + 1];
- // discarded - tbd ?
- }
- }
-
- if (hasFaceVertexUv) {
- for (var i = 0; i < nUvLayers; i++) {
- var uvLayer = f_geom.uvs[i];
- var uvs = [];
- for (var j = 0; j < nVertices; j++) {
- var uvIndex = f_faces[idx++];
- var u = uvLayer[uvIndex * 2];
- var v = uvLayer[uvIndex * 2 + 1];
- // discarded- tbd ?
- }
- }
- }
-
- if (hasFaceNormal) {
- var normalIndex = f_faces[idx++] * 3;
-
- var x = f_geom.normals[normalIndex++];
- var y = f_geom.normals[normalIndex++];
- var z = f_geom.normals[normalIndex];
-
- for (var i = 0; i < faceVertexIndices.length; i++) {
- var v = vert.get(faceVertexIndices[i]);
-
- v[4] += x;
- v[5] += y;
- v[6] += z;
- }
- }
-
- if (hasFaceVertexNormal) {
- for (var i = 0; i < nVertices; i++) {
- var normalIndex = faces[idx] * 3;
- var x = f_geom.normals[normalIndex++];
- var y = f_geom.normals[normalIndex++];
- var z = f_geom.normals[normalIndex];
-
- var v = vert.get(faces[idx]);
-
- v[4] += x;
- v[5] += y;
- v[6] += z;
-
- idx += 1;
- // face.vertexNormals.push( normal );
- }
- }
-
- if (hasFaceColor) {
- var color = f_faces[idx++];
- }
-
- if (hasFaceVertexColor) {
- for (var i = 0; i < nVertices; i++) {
- var colorIndex = faces[idx++];
- var color = f_geom.colors[colorIndex]; // ??? f_geom.colors?
- // face.vertexColors.push( color );
- }
- }
-
- var faces = null;
- if (f_faces) {
- for (var i = 1, len = f_faces.length; i < len; i++) {
- faces.push_back(f_faces[i]);
- }
- }
-
- if (f_indices) {
- faces = new dali.VectorFaceIndex();
- for (var i = 1, len = f_indices.length; i < len; i++) {
- faces.push_back(f_indices[i]);
- }
- }
-
- if (!faces) {
- faces = [];
- for (var i = 0, len = f_posns.length; i < len; i++) {
- faces.push(i);
- }
- }
-
- console.log(verts.size() + ":" + faces.size() + ":" + uuid_material);
-
- var material = this.__getMaterial(uuid_material);
- mesh.setLineData(verts, faces, material);
- }
-
- this.meshByUUID[uuid] = mesh;
- verts.delete();
- faces.delete();
- break;
- } // if uuid found
- } // for geom in geometries
- } // if uid ! in meshByUUID
-
- return this.meshByUUID[uuid];
-};
-
-ObjectLoader.prototype.delete = function() {
- "use strict";
- for (var a in this.meshByUUID) {
- a.delete();
- }
- this.meshByUUID = {};
- for (var b in this.matByUUID) {
- b.delete();
- }
- this.matByUUID = {};
-};
-
-ObjectLoader.prototype.createMeshActors = function() {
- "use strict";
- var ret = [];
- if ("object" in this.fileObject) {
- for (var i = 0, len = this.fileObject["object"]["children"].length; i < len; i++) {
- var child = this.fileObject["children"];
- if (child["type"] === "Mesh") {
- var meshData = this.__getMeshData(child["geometry"],
- child["material"]);
- ret.push(dali.__createMeshActor(meshData));
- meshData.delete();
- }
- }
- }
-
- var parent;
-
- if (ret) {
- parent = new dali.Actor();
- for (var a in ret) {
- parent.add(a);
- a.delete();
- }
- }
-
- return parent;
-};
-
-dali.createMeshActor = function(threeDjs_formatV4) {
- "use strict";
- var loader = new ObjectLoader(threeDjs_formatV4);
- return loader.createMeshActor();
-};
-
-
-
-//------------------------------------------------------------------------------
-//
-// Hit test
-//
-//------------------------------------------------------------------------------
-dali.hitTest = function(x, y) {
- "use strict";
- var a = dali.__hitTest(x, y);
- if (a.ok()) {
- dali.internalSetupProperties(a);
- return a;
- } else {
- return null;
- }
-};
-
-
-//------------------------------------------------------------------------------
-//
-// Shader support
-//
-//------------------------------------------------------------------------------
-
-/**
- * ShaderInfo class to get shader metadata.
- */
-dali.ShaderInfo = function() {
- "use strict";
-};
-
-// supported uniforms
-dali.ShaderInfo.prototype._supportedUniformTypes = ["bool",
- "int",
- "float",
- "vec2", "vec3", "vec4",
- "bvec2", "bvec3", "bvec4",
- "ivec2", "ivec3", "ivec4",
- "mat2", "mat3", "mat4",
- "sampler2D",
- "samplerCube"
- ];
-
-// need to add a value to uniform registration call
-dali.ShaderInfo.prototype._supportedUniformValues = [0,
- 0,
- 0.0,
- [0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0],
- [0, 0], [0, 0, 0], [0, 0, 0, 0],
- [0, 0], [0, 0, 0], [0, 0, 0, 0],
- [1.0, 0.0,
- 0.0, 1.0
- ],
- [1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 0.0, 1.0
- ],
- [1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0
- ]
- ];
-
-
-/**
- * Get shader metadata from compilation.
- *
- * Compiles the shader. On error set 'hasError' and error strings. On Success
- * query gl for the attributes and uniforms in the shaders.
- *
- * @param {object} gl ie from canvas.getContext("webgl")
- * @param {string} vertex shader
- * @param {string} fragment shader
- * @return {Object} shader metadata (see 'var info' below)
- */
-dali.ShaderInfo.prototype.fromCompilation = function(gl, vertex, fragment) {
- "use strict";
- var i;
- var info = {
- vertex: vertex, // vertex source code
- fragment: fragment, // fragment source code
- attributes: {}, // {aName1: {name:"aName1", ... }
- uniforms: {}, // {uName1: {name:"uName1", type:"vec2", ...}
- uniformUISpec: {}, // {uName1: {ui:"slider", min:0, max:1, ...}
- attributeCount: 0, // Number of attributes
- uniformCount: 0, // Number of uniforms
- hasError: false, // compiles without error
- vertexError: "", // Vertex compilation error
- fragmentError: "", // Fragment compilation error
- linkError: "" // Linker error
- };
-
- var vertexShader = gl.createShader(gl.VERTEX_SHADER);
- gl.shaderSource(vertexShader, vertex);
- gl.compileShader(vertexShader);
-
- // Check the compile status, return an error if failed
- if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
- info.hasError = true;
- info.vertexError = gl.getShaderInfoLog(vertexShader);
- }
-
- var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
- gl.shaderSource(fragmentShader, fragment);
- gl.compileShader(fragmentShader);
-
- // Check the compile status, return an error if failed
- if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
- info.hasError = true;
- info.fragmentError = gl.getShaderInfoLog(fragmentShader);
- }
-
- if(info.hasError) {
- gl.deleteShader(vertexShader);
- gl.deleteShader(fragmentShader);
- return info; // ==> out
- } else {
- var program = gl.createProgram();
- gl.attachShader(program, vertexShader);
- gl.attachShader(program, fragmentShader);
-
- gl.linkProgram(program);
-
- if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
- info.hasError = true;
- info.linkError = gl.getProgramInfoLog(program);
- gl.deleteProgram(program);
- gl.deleteShader(vertexShader);
- gl.deleteShader(fragmentShader);
- return info; // ==> out
- }
- }
-
- var activeUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
- var activeAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
-
- // Taken from the WebGl spec:
- // http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14
- var enums = {
- 0x8B50: "FLOAT_VEC2",
- 0x8B51: "FLOAT_VEC3",
- 0x8B52: "FLOAT_VEC4",
- 0x8B53: "INT_VEC2",
- 0x8B54: "INT_VEC3",
- 0x8B55: "INT_VEC4",
- 0x8B56: "BOOL",
- 0x8B57: "BOOL_VEC2",
- 0x8B58: "BOOL_VEC3",
- 0x8B59: "BOOL_VEC4",
- 0x8B5A: "FLOAT_MAT2",
- 0x8B5B: "FLOAT_MAT3",
- 0x8B5C: "FLOAT_MAT4",
- 0x8B5E: "SAMPLER_2D",
- 0x8B60: "SAMPLER_CUBE",
- 0x1400: "BYTE",
- 0x1401: "UNSIGNED_BYTE",
- 0x1402: "SHORT",
- 0x1403: "UNSIGNED_SHORT",
- 0x1404: "INT",
- 0x1405: "UNSIGNED_INT",
- 0x1406: "FLOAT"
- };
-
- // Loop through active uniforms
- for (i = 0; i < activeUniforms; i++) {
- var uniform = gl.getActiveUniform(program, i);
- info.uniforms[uniform.name] = {name: uniform.name,
- type: uniform.type,
- typeName: enums[uniform.type],
- size: uniform.size};
- info.uniformCount += uniform.size;
- }
-
- // Loop through active attributes
- for (i = 0; i < activeAttributes; i++) {
- var attribute = gl.getActiveAttrib(program, i);
- info.attributes[attribute.name] = {name: attribute.name,
- type: attribute.type,
- typeName: enums[attribute.type],
- size: attribute.size};
- info.attributeCount += attribute.size;
- }
-
- // uniformUISpec
- this._addUniformMetaData(vertex, info);
- this._addUniformMetaData(fragment, info);
-
- return info;
-};
-
-/*
- * add unform metadata from shader source comments
- * ie return as an object the comment following a uniform
- * uniform float uAlpha; // {"min":0, "max":1}
- */
-/** private */
-dali.ShaderInfo.prototype._addUniformMetaData = function(src, metadata) {
- "use strict";
- // Loop through active uniforms
- for(var name in metadata.uniforms) {
- var reguniform = new RegExp(name + "[^;]*;(.*)");
-
- var tmp = reguniform.exec(src);
- if(tmp && tmp[1]) {
- var meta;
- var uComments = tmp[1].trim();
- if(uComments.startsWith("//")) { // meta data in comments
- try {
- meta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
- if(typeof meta !== typeof ({})) {
- throw ("Uniform UI Spec in comments must be an object");
- }
- } catch (e) {
- meta = {};
- }
- } else {
- meta = {};
- }
- metadata.uniformUISpec[name] = meta;
- }
- }
-};
-
-/**
- * Get shader metadata from regex search.
- *
- * Attempts a regex search to get the shader meta data.
- * Use fromCompilation() instead of this function wherever compilation is
- * possible as this approach will never work for all shaders.
- * Does no compilation or error checking but retains fields for
- * compatibility with .fromCompilation(...)
- * May return an error if the regex fails.
- *
- * @param {string} vertex shader
- * @param {string} fragment shader
- * @return {Object} shader metadata (see 'var info' below)
- */
-dali.ShaderInfo.prototype.fromRegEx = function(vertex, fragment) {
- "use strict";
- var info = { // similar to this.fromCompilation()
- vertex: vertex, // source code
- fragment: fragment,
- attributes: {}, // {aName1: {name:"aName1", ... }
- uniforms: {}, // {uName1: {name:"uName1", type:"vec2", ...}
- attributeCount: 0,
- uniformCount: 0,
- uniformUISpec: {}, // {uName1: {ui:"slider", min:0, max:1, ...}
- hasError: false, // compiles without error
- vertexError: "",
- fragmentError: "",
- linkError: ""
- };
-
- var metaVertex;
- try {
- metaVertex = this._getRegExMetaData(vertex);
- } catch(e) {
- info.hasError = true;
- info.vertexError = e.message;
- return info;
- }
-
- var metaFragment;
- try {
- metaFragment = this._getRegExMetaData(fragment);
- } catch(e) {
- info.hasError = true;
- info.fragmentError = e.message;
- return info;
- }
-
- var name;
-
- // merge
- info.uniforms = metaVertex.uniformMetaData;
- info.uniformUISpec = metaVertex.uniformUISpec;
-
- for(name in metaFragment.uniformMetaData) {
- if( name in info.uniforms ) {
- info.uniforms[name] = dali.mergeObjects(info.uniforms[name], metaVertex.uniformMetaData);
- } else {
- info.uniforms[name] = metaFragment.uniformMetaData[name];
- }
- if( name in info.uniformUISpec ) {
- info.uniformUISpec[name] = dali.mergeObjects(info.uniformUISpec[name], metaVertex.uniformUISpec);
- } else {
- info.uniformUISpec[name] = metaFragment.uniformUISpec[name];
- }
- }
-
- info.attributes = metaVertex.attributeMetaData;
- for(name in metaFragment.attributeMetaData) {
- if( name in metaVertex.attributeMetaData ) {
- info.attributes[name] = dali.mergeObjects(info.attributes[name], metaVertex.attributeMetaData);
- } else {
- info.attributes[name] = metaFragment.attributeMetaData[name];
- }
- }
-
- return info;
-};
-
-/*
- * Returns a string with all comments removed
- */
-/** private */
-dali.ShaderInfo.prototype._removeComments = function(str) {
- "use strict";
- var uid = "_" + new Date(),
- primatives = [],
- primIndex = 0;
-
- return (
- str
- /* Remove strings */
- .replace(/(['"])(\\\1|.)+?\1/g, function(match){
- primatives[primIndex] = match;
- return (uid + "") + primIndex++;
- })
-
- /* Remove Regexes */
- .replace(/([^\/])(\/(?!\*|\/)(\\\/|.)+?\/[gim]{0,3})/g, function(match, $1, $2){
- primatives[primIndex] = $2;
- return $1 + (uid + "") + primIndex++;
- })
-
- /*
- - Remove single-line comments that contain would-be multi-line delimiters
- E.g. // Comment /* <--
- - Remove multi-line comments that contain would be single-line delimiters
- E.g. /* // <--
- */
- .replace(/\/\/.*?\/?\*.+?(?=\n|\r|$)|\/\*[\s\S]*?\/\/[\s\S]*?\*\//g, "")
-
- /*
- Remove single and multi-line comments,
- no consideration of inner-contents
- */
- .replace(/\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g, "")
-
- /*
- Remove multi-line comments that have a replace ending (string/regex)
- Greedy, so no inner strings/regexes will stop it.
- */
- .replace(RegExp("\\/\\*[\\s\\S]+" + uid + "\\d+", "g"), "")
-
- /* Bring back strings & regexes */
- .replace(RegExp(uid + "(\\d+)", "g"), function(match, n){
- return primatives[n];
- })
- );
-};
-
-/*
- * Returns true if value is in the array
- */
-/** private */
-dali.ShaderInfo.prototype._contains = function(array, value) {
- "use strict";
- for(var i = 0; i < array.length; i++) {
- if(array[i] === value) {
- return true;
- }
- }
- // else
- return false;
-};
-
-/*
- * Get the src meta data for unforms and attributes armed only with a regexp
- */
-/** private */
-dali.ShaderInfo.prototype._getRegExMetaData = function(src) {
- "use strict";
- var ret = {"uniforms": [], // ["uName1", ["uName2"]
- "uniformMetaData": {}, // {uName1: {type:"vec3,...}
- "uniformUISpec": {}, // {ui:"slider", min:..., max:...}
- "attributes": [], // ["aName2"]
- "attributeMetaData": {} // ["aName2"]
- };
-
- // Undoubtedly this approach will be wrong. Hopefully on not too many corner cases...
- // A better way is to compile the source see (fromCompilation())
- // but that requres a gl context.
- var tmp;
-
- var definesOut = /#define[ \t]+([A-Za-z_0-9]*)[ \t]+(.*)/g;
-
- var reg = /[ \t]?uniform[ ]*((?:lowp|mediump|highp)?[ \t]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t]*([A-Za-z0-9]*))[ \t]*(;|\[.*\][ \t]*;)(.*)/gi;
-
- var regAttrib = /[ \t]?attribute[ ]*((?:lowp|mediump|highp)?[ \t]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t]*([A-Za-z0-9]*))[ \t]*(;|\[.*\][ \t]*;)(.*)/gi;
-
- // 1. no commented out uniforms
- var noCommentSource = this._removeComments(src);
-
- var validUniforms = [];
- while ((tmp = reg.exec(noCommentSource))) {
- validUniforms.push( tmp[3] );
- }
-
- while ((tmp = regAttrib.exec(noCommentSource))) {
- ret.attributes.push( tmp[3] );
- ret.attributeMetaData[ tmp[3] ] = {name: tmp[3], type: tmp[2] };
- }
-
- // 2. replace defines
- var defines = [];
- while ((tmp = definesOut.exec(noCommentSource))) {
- defines.push([tmp[1], tmp[2]]);
- }
- var defineDict = {};
- var defineList = [];
- while(defines.length) {
- var p = defines.pop();
- var n = p[0];
- var v = p[1];
- try {
- defineDict[n] = eval(v);
- defineList.push([n, defineDict[n]]);
- } catch(e) {
- var d = /([A-Za-z]+[A-Za-z0-9]*)/g;
- while ((tmp = d.exec(v))) {
- if(tmp[0] in defineDict) {
- v = v.replace(tmp[0], defineDict[tmp[0]]);
- } else {
- defines.push(p); // stick it back to try again. ...and endless loop if we can't(!)
- }
- }
- }
- }
-
- for(var i = 0; i < defineList.length; i++) {
- var re = new RegExp(defineList[i][0], "g");
- src = src.replace(re, defineList[i][1]);
- }
-
- // 3. get uniforms
- while ((tmp = reg.exec(src))) {
- if(!this._contains(validUniforms, tmp[3])) {
- continue;
- }
- var uType = tmp[2];
- var uName = tmp[3];
- var uArray = tmp[4].slice(0, -1);
- var uComments = tmp[5].trim();
- var meta;
- var uiSpecMeta = null;
- if(uComments.startsWith("//")) { // meta data in comments
- uiSpecMeta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
- if(typeof uiSpecMeta !== typeof ({})) {
- throw ("Uniform UI Spec in comments must be an object");
- }
- }
-
- if(uiSpecMeta) {
- uiSpecMeta.name = tmp[3];
- ret.uniformUISpec[uName] = uiSpecMeta;
- }
-
- meta = {};
- meta.type = tmp[2];
- meta.name = tmp[3];
- meta.count = 0;
-
- var name;
- if(uArray.search("[[]") >= 0) { // an array
- meta.count = Number(uArray.slice(1, -1));
- }
-
- if(this._contains( this._supportedUniformTypes, uType) ) {
- if(meta.count !== 0) { // array
- for(var j = 0; j < meta.count; j++) {
- ret.uniforms.push( meta.name );
- ret.uniformMetaData[ meta.name ] = {type: meta.type,
- name: meta.name + "[" + j + "]",
- index: j,
- count: meta.count};
- }
- } else {
- ret.uniforms.push( meta.name );
- ret.uniformMetaData[ meta.name ] = {type: meta.type,
- name: meta.name,
- index: 0,
- count: 0};
- }
- } else {
- // not a base type so need to get the compound type
- var structFind = new RegExp( "(struct[ \t\n]*" + uType + "[^{]*{)([^}]*)", "g");
- var structLines = structFind.exec(src)[2].split(";");
- var structUniforms = [];
- var tmpStruct;
- var k;
- for(var lineNo = 0; lineNo < structLines.length; lineNo++) {
- var line = structLines[lineNo].replace(/\n/g, "") + ";";
- if(line !== ";") {
- var structReg = /[ \t\n]*((?:lowp|mediump|highp)?[ \t\n]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t\n]*([A-Za-z0-9]*))[ \t\n]*(;|\[.*\][ \t\n]*;)/gi;
- while ((tmpStruct = structReg.exec(line))) {
- structUniforms.push( { type: tmpStruct[2],
- name: tmpStruct[3],
- count: meta.count } );
- }
- }
- }
- if(meta.count === 0) {
- for(k = 0; k < structUniforms.length; k++) {
- name = uName + "." + structUniforms[k].name;
- ret.uniforms.push( name );
- ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
- name: name,
- count: meta.count,
- index: 0,
- structType: meta.type,
- structName: meta.name};
- }
- } else { // array
- for(var l = 0; l < meta.count; l++) {
- for(k = 0; k < structUniforms.length; k++) {
- name = uName + "[" + l + "]" + "." + structUniforms[k].name;
- ret.uniforms.push( name );
- ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
- name: name,
- count: meta.count,
- index: l,
- structType: meta.type,
- structName: meta.name};
- }
- }
- }
- }
- }
-
- return ret;
-};
-
-//------------------------------------------------------------------------------
-//
-// Debug Module
-//
-//------------------------------------------------------------------------------
-dali.Debug = function() {
- "use strict";
-};
-
-dali.Debug.prototype.printTypeProperties = function(typeName) {
- "use strict";
- var t = new dali.TypeRegistry();
- var info = t.getTypeInfo(typeName);
- var props = info.getProperties();
- for (var i = 0; i < props.size(); i++) {
- console.log(i + ":" + props.get(i));
- }
- info.delete(); // wrapper
- t.delete(); // wrapper
-};
-
-dali.Debug.prototype.printProperties = function(o) {
- "use strict";
- var props = o.getProperties();
-
- var len = props.size();
- for(var i = 0; i < len; i++) {
- var name = props.get(i);
- var type = o.getPropertyTypeName(name);
- if(type !== "NONE") {
- console.log(i + ":" + name + " " + type);
- } else {
- type = o.getPropertyTypeName(name);
- console.log(i + ":" + name + " " + type + " (Not mangled)");
- }
- }
- props.delete(); // wrapper
-};
-
-dali.Debug.prototype.printTypes = function() {
- "use strict";
-
- var t = new dali.TypeRegistry();
- for (var i = 0; i < t.getTypeNameCount(); i++) {
- console.log(t.getTypeName(i));
- }
- t.delete(); // wrapper
-};
-
-
-dali._debugPrintParents = function(actor, list) {
- "use strict";
- var p = null;
-
- if (!actor.ok()) {
- return;
- }
-
- try {
- p = actor.getParent();
- if (!p.ok()){
- p = null;
- }
- } catch (e) {
- // console.log("Cannot get parent", e);
- }
-
- if (p) {
- list.push(p);
- dali._debugPrintParents(p, list);
- }
-};
-
-dali.Debug.prototype.printTree = function(actor) {
- "use strict";
- var l = [];
- dali._debugPrintParents(actor, l);
- var a;
- var ti;
- console.log("---");
- for (var i = l.length - 1; i >= 0; i--) {
- a = l[i];
- ti = a.getTypeInfo();
- console.log("|", Array(l.length - i).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
- ti.delete();
- }
- ti = actor.getTypeInfo();
- console.log("*", Array(l.length + 1).join("*"), ti.getName(), "P", actor.position, "R", actor.orientation, actor.name);
- ti.delete();
-
- var children = actor.getChildren();
- for (var j = 0; j < children.length; j++) {
- a = children[j];
- ti = a.getTypeInfo();
- console.log("|", Array(l.length + 1 + 1 + j).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
- ti.delete();
- }
-};
-
-dali.Debug.prototype.printRenderTask = function(rendertask) {
- "use strict";
- console.log("[X,Y]", rendertask.getCurrentViewportPosition());
- console.log("[W,H]", rendertask.getCurrentViewportSize());
-
- var c = rendertask.getCameraActor();
- if (!c.ok()) {
- console.log("No Camera");
- } else {
- console.log("Camera Pos:", c.position);
- console.log("Camera Rot:", c.orientation);
- console.log("Camera Inherit:", c.inheritRotation);
- console.log("Camera ParentOrigin:", c.parentOrigin);
- console.log("Camera AnchorPoint:", c.anchorPoint);
- var p = null;
- try {
- p = c.getParent();
- if(!p.ok()) {
- p = null;
- }
- } catch (e) {
- console.log("Cannot get parent", e);
- }
-
- if (!p) {
- console.log("Camera has no parent?");
- } else {
- var ti = p.getTypeInfo();
- console.log("Parent Name", ti.getName());
- ti.delete();
- p.delete();
- }
- }
-};
-
-dali.Debug.prototype.printRenderTasks = function() {
- "use strict";
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
- for (var i = 0; i < taskList.getTaskCount(); i++) {
- var t = taskList.getTask(i);
- console.log("RenderTask:", i);
- this.printRenderTask(t);
- t.delete(); // wrapper
- }
- taskList.delete(); // wrapper
-};
-
-dali.Debug.prototype.findFirstActor = function(actor, predicateFunction) {
- "use strict";
- for (var i = 0, len = actor.getChildCount(); i < len; i++) {
- var a = actor.getChildAt(i);
- var found = predicateFunction(a);
- if (found) {
- return a;
- }
- var child = this.findFirstActor(a, predicateFunction);
- if (child) {
- return child;
- }
- a.delete();
- }
- return null;
-};
-
-dali.Debug.prototype.depthVisit = function(actor, operation, dontDelete) {
- "use strict";
- for (var i = 0, len = actor.getChildCount(); i < len; i++) {
- var a = actor.getChildAt(i);
- var done = operation(a);
- if (!done) {
- return false;
- }
- if (!this.depthVisit(a, operation, dontDelete)) {
- return false;
- }
- var doit = true;
- if (dontDelete !== undefined) {
- if (dontDelete) {
- doit = false;
- }
- }
- if (doit) {
- a.delete();
- }
- }
- return true;
-};
-
-dali.operationPrintProperty = function(property, all) {
- "use strict";
- return (function(actor) {
- if (property in actor) {
- dali.log(actor.getId() + "property:" + actor[property]);
- } else {
- dali.log(actor.getId() + "property:n/a");
- }
- return all;
- });
-};
-
-dali.predicatePropertyEquals = function(property, value) {
- "use strict";
- return (function(actor) {
- if (property in actor) {
- if (actor[property] === value) {
- return true;
- }
- }
- return false;
- });
-};
-
-dali.typeInheritsFrom = function(type, basename) {
- var inherits = false;
-
- var registry = new dali.TypeRegistry();
-
- var base = registry.getTypeInfo( type.getBaseName() );
-
- if(base.ok())
- {
- inherits = (base.getName() === basename);
-
- while(!inherits)
- {
- base = registry.getTypeInfo( base.getBaseName() );
- if(base.ok())
- {
- inherits = (base.getName() === basename);
- }
- else
- {
- break;
- }
- }
- }
-
- return inherits;
-};
-
-
-
-//------------------------------------------------------------------------------
-//
-// View Module
-//
-// Helper functions for creating front/top/left views with RenderTasks
-//
-//------------------------------------------------------------------------------
-
-/**
- * Sets the clear colour in a RenderTask
- * @method setClearColor
- * @param {int} renderTaskIndex
- * @param {array} color The rgba colour array
- */
-dali.setClearColor = function(renderTaskIndex, color) {
- "use strict";
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
- if (renderTaskIndex >= taskList.getTaskCount()) {
- console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
- taskList.delete(); // wrapper
- return;
- }
- var rendertask = taskList.getTask(renderTaskIndex);
- rendertask.setClearEnabled(true);
- rendertask.setClearColor(color);
-};
-
-/**
- * Gets the clear colour of a RenderTask
- * @method setClearColor
- * @param {int} renderTaskIndex
- * @return {array} The rgba colour array
- */
-dali.getClearColor = function(renderTaskIndex) {
- "use strict";
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
- if (renderTaskIndex >= taskList.getTaskCount()) {
- console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
- taskList.delete(); // wrapper
- return null;
- }
- var rendertask = taskList.getTask(renderTaskIndex);
- return rendertask.getClearColor();
-};
-
-/**
- * Set a front view camera with viewport x,y,w,h
- * @method setFrontView
- * @param {int} renderTaskIndex
- * @param {int} x Viewport X
- * @param {int} y Viewport Y
- * @param {int} w Viewport W
- * @param {int} h Viewport H
- */
-dali.setFrontView = function(renderTaskIndex, x, y, w, h) {
- "use strict";
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
- if (renderTaskIndex >= taskList.getTaskCount()) {
- console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
- taskList.delete(); // wrapper
- return;
- }
- var rendertask = taskList.getTask(renderTaskIndex);
-
- var c = rendertask.getCameraActor();
- assert(c.ok(), "Rendertask has no valid camera actor");
-
- rendertask.setViewportPosition([x, y]);
- rendertask.setViewportSize([w, h]);
- c.position = [0, 0, 800];
- c.orientation = [0, 1, 0, 180];
- c.aspectRatio = w / h;
-
- c.delete(); // wrapper
- rendertask.delete(); // wrapper
- taskList.delete(); // wrapper
-};
-
-/**
- * Set a top view camera with viewport x,y,w,h
- * @method setTopView
- * @param {int} renderTaskIndex
- * @param {int} x Viewport X
- * @param {int} y Viewport Y
- * @param {int} w Viewport W
- * @param {int} h Viewport H
- */
-dali.setTopView = function(renderTaskIndex, x, y, w, h) {
- "use strict";
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
- if (renderTaskIndex >= taskList.getTaskCount()) {
- console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
- taskList.delete(); // wrapper
- return;
- }
- var rendertask = taskList.getTask(renderTaskIndex);
-
- var c = rendertask.getCameraActor();
- assert(c.ok(), "Rendertask has no valid camera actor");
-
- rendertask.setViewportPosition([x, y]);
- rendertask.setViewportSize([w, h]);
-
- var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
- var q2 = dali.axisAngleToQuaternion([1, 0, 0, dali.radian(-90)]); // pitch to look at scene
- var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
-
- c.position = [0, -800, 0]; // @todo; get 800 from dali not hard coded here
- c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
- c.aspectRatio = w / h;
-
- c.delete(); // wrapper
- rendertask.delete(); // wrapper
- taskList.delete(); // wrapper
-};
-
-/**
- * Set a right view camera with viewport x,y,w,h
- * @method setRightView
- * @param {int} renderTaskIndex
- * @param {int} x Viewport X
- * @param {int} y Viewport Y
- * @param {int} w Viewport W
- * @param {int} h Viewport H
- */
-dali.setRightView = function(renderTaskIndex, x, y, w, h) {
- "use strict";
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
- if (renderTaskIndex >= taskList.getTaskCount()) {
- console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
- taskList.delete(); // wrapper
- return;
- }
- var rendertask = taskList.getTask(renderTaskIndex);
-
- var c = rendertask.getCameraActor();
- assert(c.ok(), "Rendertask has no valid camera actor");
-
- rendertask.setViewportPosition([x, y]);
- rendertask.setViewportSize([w, h]);
-
- var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
- var q2 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(90)]); // yaw again to look from right
- var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
-
- c.position = [800, 0, 0];
- c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
- c.aspectRatio = w / h;
-
- c.delete(); // wrapper
- rendertask.delete(); // wrapper
- taskList.delete(); // wrapper
-};
-
-/**
- * Remove all but one render task. Presumes RenderTasks are being use only for viewing windows.
- * @method onePane
- */
-dali.onePane = function() {
- "use strict";
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
- var tasks = [];
- var i, len;
-
- for (i = 1, len = taskList.getTaskCount(); i < len; i++) {
- tasks.push(taskList.getTask(i));
- }
-
- for (i = 0, len = tasks.length; i < len; i++) {
- var task = tasks[i];
- // delete the camera actors we created in twoPane and threePane
- var c = task.getCameraActor();
- if (c.ok()) {
- var p = c.getParent();
- if (p.ok()) {
- p.remove(c);
- }
- p.delete(); // wrapper
- }
- c.delete(); // wrapper
-
- taskList.removeTask(task);
- task.delete(); // wrapper
- }
-
- taskList.delete();
-};
-
-/**
- * Creates render tasks and cameras for a two pane view.
- * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
- * (in a separate function to allow window gutters)
- * @method twoPane
- */
-dali.twoPane = function() {
- "use strict";
- dali.onePane();
-
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
-
- var defaultTask = taskList.getTask(0);
- var defaultCamera = defaultTask.getCameraActor();
- var defaultCameraParent = defaultCamera.getParent();
-
- var t;
- t = taskList.createTask();
-
- var c = new dali.CameraActor(); // add camera for different viewpoint
- c.position = [0, 0, 800];
- c.orientation = [0, 1, 0, 180];
- c.parentOrigin = [0.5, 0.5, 0.5];
- c.anchorPoint = [0.5, 0.5, 0.5];
- t.setCameraActor(c);
- defaultCameraParent.add(c);
- c.delete(); // wrapper
-
- t.delete(); // wrapper
-
- defaultCameraParent.delete(); // wrapper
- defaultCamera.delete(); // wrapper
- defaultTask.delete(); // wrapper
-
- taskList.delete(); // wrapper
-};
-
-/**
- * Creates render tasks and cameras for a three pane view.
- * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
- * (in a separate function to allow window gutters)
- * @method threePane
- */
-dali.threePane = function() {
- "use strict";
- dali.onePane();
-
- var stage = dali.stage;
- var taskList = stage.getRenderTaskList();
-
- var defaultTask = taskList.getTask(0);
- var defaultCamera = defaultTask.getCameraActor();
- var defaultCameraParent = defaultCamera.getParent();
-
- var t;
- t = taskList.createTask();
-
- var c = new dali.CameraActor(); // add camera for different viewpoint
- c.position = [0, 0, 800];
- c.orientation = [0, 1, 0, 180];
- c.parentOrigin = [0.5, 0.5, 0.5];
- c.anchorPoint = [0.5, 0.5, 0.5];
- t.setCameraActor(c);
- defaultCameraParent.add(c);
- c.delete(); // wrapper
-
- t.delete(); // wrapper
-
- t = taskList.createTask();
-
- c = new dali.CameraActor(); // add camera for different viewpoint
- c.position = [0, 0, 800];
- c.orientation = [0, 1, 0, 180];
- c.parentOrigin = [0.5, 0.5, 0.5];
- c.anchorPoint = [0.5, 0.5, 0.5];
- t.setCameraActor(c);
- defaultCameraParent.add(c);
- c.delete(); // wrapper
-
- t.delete(); // wrapper
-
- defaultCameraParent.delete(); // wrapper
- defaultCamera.delete(); // wrapper
- defaultTask.delete(); // wrapper
-
- taskList.delete(); // wrapper
-};
-
-//------------------------------------------------------------------------------
-//
-// Dali Initialization Module
-//
-//------------------------------------------------------------------------------
-
-/**
- * Create a Dali object by type name
- * @method create
- * @param {string} name The type name to create
- * @return A Dali handle to the Dali object
- */
-dali.create = function(name) {
- "use strict";
-
- var handle = dali.__createActor(name);
-
- if (!handle.ok()) {
- handle.delete(); // handle
- handle = dali.__createHandle(name);
- }
-
- dali.internalSetupProperties(handle);
-
- return handle;
-};
-
-dali.updateFrame = function() {
- dali.__updateOnce();
- dali.__renderOnce();
-};
-
-/**
- * Creates constructors for objects found in the TypeRegistry. Some objects are
- * individually wrapped. Sets some global objects eg. debug/stage.
- */
-/** private */
-dali.init = function() {
- "use strict";
-
- console.log( dali.VersionString() );
-
- dali.jsSignalHolder = new dali.SignalHolder(); // for js callbacks
-
- dali.debug = new dali.Debug();
-
- dali.stage = new dali.Stage();
-
- dali.getStage = function() { // duplication of dali.stage to stop regressions
- return dali.stage;
- };
-
- //
- // Add constructor functions to dali from the type registry
- //
- // Uses separate create functions to add methods for the different base classes.
- // Other generic access is by properties. Currently
- //
- // +------------+
- // | BaseHandle |
- // +------+-----+
- // |
- // |--------------+------------|
- // | | |
- // +----+------+ +----+---+ +----+--+
- // | Animation | | Handle | | Image |
- // +-----------+ +--------+ +-------+
- //
-
- var t = new dali.TypeRegistry();
-
- // use the emscripten wrapping for these and not the typeregisitry creation function
- var useWrapping = { RenderTask: 1, RenderTaskList: 1, CameraActor: 1,
- TypeInfo: 1,
- Path: 1, Animation: 1,
- Handle: 1, Actor: 1,
- PropertyMap: 1, PropertyBuffer: 1,
- Image: 1, BufferImage: 1, EncodedBufferImage: 1,
- Geometry: 1, Material: 1, Shader: 1, Sampler: 1, Renderer: 1
- };
-
- for (var i = 0; i < t.getTypeNameCount(); i++) {
- // anon function because of closure with defineProperty
- // (if just variable in loop then the variable 'address' is captured, not the value
- // so it becomes last value set)
- (function(name) {
- var createFunc;
- var info = t.getTypeInfo(name);
-
- if(dali.typeInheritsFrom(info, "Actor")) {
- createFunc = dali.__createActor;
- } else if(dali.typeInheritsFrom(info, "Handle")) {
- createFunc = dali.__createHandle;
- }
-
- // @todo Dali error?? name lengths should never be zero
- if (name.length && !(name in useWrapping) ) {
- Object.defineProperty(dali, name, {
- enumerable: true,
- configurable: false,
- get: function() {
- return function() {
- // console.log(name);
- return dali.create(name);
- };
- }
- });
- }
- })(t.getTypeName(i));
- }
-
- dali.updateFrame();
-
-}(); // call init
-
-
-//------------------------------------------------------------------------------
-//
-// Post run
-//
-// Call postDaliWrapperRun() to indicate dali-wrapper.js has loaded
-// and other sequential tasks can run (js files can load async)
-//
-//------------------------------------------------------------------------------
-if(Module)
-{
- if (Module.postDaliWrapperRun) {
- Module.postDaliWrapperRun();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "emscripten-utils.h"
-
-// EXTERNAL INCLUDES
-
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-Dali::Image CreateImageRGBA(unsigned int width, unsigned int height, const std::string& data)
-{
- Dali::BufferImage b = Dali::BufferImage::New( width, height, Dali::Pixel::RGBA8888 );
-
- const Dali::PixelBuffer* from = reinterpret_cast<const Dali::PixelBuffer*>( data.c_str() );
- Dali::PixelBuffer* to = b.GetBuffer();
-
- unsigned int len = std::max( width * height * 4, data.size() );
- for(int i = 0; i < len; i++)
- {
- *to++ = *from++;
- }
- return b;
-}
-
-Dali::Image CreateImageRGB(unsigned int width, unsigned int height, const std::string& data)
-{
- Dali::BufferImage b = Dali::BufferImage::New( width, height, Dali::Pixel::RGB888 );
-
- const Dali::PixelBuffer* from = reinterpret_cast<const Dali::PixelBuffer*>( data.c_str() );
- Dali::PixelBuffer* to = b.GetBuffer();
-
- unsigned int len = std::max( width * height * 3, data.size() );
- for(int i = 0; i < len; i++)
- {
- *to++ = *from++;
- }
- return b;
-}
-
-Dali::Image GetImage(const std::string& data)
-{
- const uint8_t* const ptr = reinterpret_cast<const uint8_t * const>(data.c_str());
- return Dali::EncodedBufferImage::New(ptr, data.size());
-}
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_EMSCRIPTEN_UTILS_H__
-#define __DALI_EMSCRIPTEN_UTILS_H__
-
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-#include <dali/public-api/dali-core.h>
-#include "emscripten/val.h"
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Creates a Dali RGBA Image from raw bytes
- *
- * @param[in] width The image width
- * @param[in] height The image height
- * @param[in] data The byte data
- * @returns The Dali Image
- *
- */
-Dali::Image CreateImageRGBA(unsigned int width, unsigned int height, const std::string& data);
-
-/**
- * Creates a Dali RGB Image from raw bytes
- *
- * @param[in] width The image width
- * @param[in] height The image height
- * @param[in] data The byte data
- * @returns The Dali Image
- *
- */
-Dali::Image CreateImageRGB(unsigned int width, unsigned int height, const std::string& data);
-
-/**
- * Creates a dali Image from encoded bytes (ie jpg/png etc)
- *
- * @param[in] data The byte data
- *
- * @returns The Dali Image
- *
- */
-Dali::Image GetImage(const std::string& data);
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-/*
- * Copyright (c) 2016 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 "geometry-wrapper.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-void SetIndexBufferDataRaw(Dali::Geometry& self, const std::string& data, std::size_t size )
-{
- self.SetIndexBuffer( reinterpret_cast<unsigned short*>( const_cast<char*>(data.c_str()) ), size );
-}
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_GEOMETRY_WRAPPER_H__
-#define __DALI_GEOMETRY_WRAPPER_H__
-
-/*
- * Copyright (c) 2016 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/dali-core.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/val.h"
-#include "emscripten/bind.h"
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Sets the index buffer
- *
- * @param[in] self The Geometry
- * @param[in] data The raw byte data
- *
- */
-void SetIndexBufferDataRaw(Dali::Geometry& self, const std::string& data, std::size_t size );
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "handle-wrapper.h"
-
-// EXTERNAL INCLUDES
-#include <sstream>
-#include <dali/devel-api/scripting/scripting.h>
-
-// INTERNAL INCLUDES
-#include "type-info-wrapper.h"
-#include "property-value-wrapper.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-bool BaseHandleOk(Dali::BaseHandle& self)
-{
- return self;
-}
-
-void SetSelf(Dali::Handle& self, Dali::Handle& other)
-{
- self = other;
-}
-
-void SetProperty(Dali::Handle& self, const std::string& name, const Dali::Property::Value& value)
-{
- DALI_ASSERT_ALWAYS(self);
- if( self )
- {
- Dali::Property::Index index = self.GetPropertyIndex(name);
-
- if( Dali::Property::INVALID_INDEX != index )
- {
- self.SetProperty(index, value);
- }
- else
- {
- printf("ERR Invalid property name:%s", name.c_str());
- EM_ASM( throw "Invalid property name (HandleWrapper::SetProperty)" );
- }
- }
- else
- {
- EM_ASM( throw "ActorWrapper has no actor" );
- }
-
-}
-
-Dali::Property::Value GetProperty(Dali::Handle& self, const std::string& name)
-{
- DALI_ASSERT_ALWAYS(self);
- Dali::Property::Value ret;
- if( self )
- {
- Dali::Property::Index index = self.GetPropertyIndex(name);
-
- if( Dali::Property::INVALID_INDEX != index )
- {
- ret = self.GetProperty(index);
- }
- else
- {
- printf("ERR Invalid property name:%s", name.c_str());
- EM_ASM( throw new Error("Invalid property name (HandleWrapper::GetProperty)") );
- }
- }
- else
- {
- EM_ASM( throw new Error("ActorWrapper has no actor") );
- }
-
- return ret;
-}
-
-int GetPropertyIndex(Dali::Handle& self, const std::string& name)
-{
- if( self )
- {
- Dali::Property::Index index = self.GetPropertyIndex(name);
-
- return (int)index; // self.GetPropertyIndex(name);
- }
-
- return -1;
-}
-
-std::vector<std::string> GetProperties(Dali::Handle& self)
-{
- Dali::Property::IndexContainer indices;
- self.GetPropertyIndices( indices );
- std::vector<std::string> names;
- for(Dali::Property::IndexContainer::Iterator iter(indices.Begin()); iter != indices.End(); ++iter)
- {
- std::string name = self.GetPropertyName( *iter );
-
- names.push_back(name);
- }
- return names;
-}
-
-std::string GetPropertyTypeName(Dali::Handle& self, const std::string& name)
-{
- if(self)
- {
- Dali::Property::Index index = self.GetPropertyIndex(name);
- if(Dali::Property::INVALID_INDEX != index)
- {
- return Dali::PropertyTypes::GetName(self.GetPropertyType(index));
- }
- }
-
- // if we got here
- return Dali::PropertyTypes::GetName(Dali::Property::NONE);
-}
-
-Dali::Property::Type GetPropertyTypeFromName(Dali::Handle& self, const std::string& name)
-{
- Dali::Property::Type type = Dali::Property::NONE;
-
- if(self)
- {
- Dali::Property::Index index = self.GetPropertyIndex(name);
- if(Dali::Property::INVALID_INDEX != index)
- {
- type = self.GetPropertyType(index);
- }
- }
-
- return type;
-}
-
-Dali::Property::Index RegisterProperty(Dali::Handle& self, const std::string& name, const Dali::Property::Value& propertyValue)
-{
- Dali::Property::Index ret = Dali::Property::INVALID_INDEX;
-
- Dali::Property::Type type = propertyValue.GetType();
- if(Dali::Property::ARRAY == type || Dali::Property::MAP == type)
- {
- // these types would need support in the javascript side of the wrapper
- EM_ASM( throw "Property type not supported" );
- }
-
- if(self)
- {
- ret = self.RegisterProperty(name, propertyValue, Dali::Property::AccessMode::READ_WRITE);
- }
- return ret;
-}
-
-Dali::TypeInfo GetTypeInfo(Dali::Handle& self)
-{
- Dali::TypeInfo ret;
- if( self )
- {
- self.GetTypeInfo(ret);
- }
- return ret;
-}
-
-Dali::Property::Index RegisterAnimatedProperty(Dali::Handle& self, const std::string& name, const Dali::Property::Value& propertyValue)
-{
- Dali::Property::Index ret = Dali::Property::INVALID_INDEX;
-
- Dali::Property::Type type = propertyValue.GetType();
- if(Dali::Property::ARRAY == type || Dali::Property::MAP == type)
- {
- // these types would need support in the javascript side of the wrapper
- EM_ASM( throw "Property type not supported" );
- }
-
- if(self)
- {
- ret = self.RegisterProperty(name, propertyValue, Dali::Property::AccessMode::ANIMATABLE);
- }
- return ret;
-}
-
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_HANDLE_WRAPPER_H__
-#define __DALI_HANDLE_WRAPPER_H__
-
-/*
- * Copyright (c) 2015 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/dali-core.h>
-
-#include "emscripten/emscripten.h"
-#include "emscripten/bind.h"
-
-// INTERNAL INCLUDES
-#include "type-info-wrapper.h"
-
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Checks if a handle is pointing somewhere
- *
- * @param[in] self The basehandle
- * @returns true if the handle is not empty
- *
- */
-bool BaseHandleOk(Dali::BaseHandle& self);
-
-/**
- * Sets a handle to point to another object
- *
- * @param[in] self The handle to change
- * @param[in] self The handle to point to
- *
- */
-void SetSelf(Dali::Handle& self, Dali::Handle& other);
-
-/**
- * Sets a property by name
- *
- * @param[in] self The handle
- * @param[in] javascriptName The property by name
- * @param[in] value The property value
- *
- */
-void SetProperty(Dali::Handle& self, const std::string& javascriptName, const Dali::Property::Value& value);
-
-/**
- * Gets a property by name
- *
- * @param[in] self The handle
- * @param[in] javascriptName The property by name
- * @returns The property value
- *
- */
-Dali::Property::Value GetProperty(Dali::Handle& self, const std::string& javascriptName);
-
-/**
- * Gets a property index
- *
- * @param[in] self The handle
- * @param[in] javascriptName The property by name
- * @returns The property index
- *
- */
-int GetPropertyIndex(Dali::Handle& self, const std::string& javascriptName);
-
-/**
- * Gets a list of property names
- *
- * @param[in] self The handle
- * @returns The list of property names
- *
- */
-std::vector<std::string> GetProperties(Dali::Handle& self);
-
-/**
- * Gets a property type by name
- *
- * @param[in] self The handle
- * @param[in] name The property type name
- * @returns The property type
- *
- */
-Dali::Property::Type GetPropertyTypeFromName(Dali::Handle& self, const std::string& name);
-
-/**
- * Gets a property type name
- *
- * @param[in] self The handle
- * @param[in] name The property by name
- * @returns The property type name
- *
- */
-std::string GetPropertyTypeName(Dali::Handle& self, const std::string& name);
-
-/**
- * Registers a property by name
- *
- * @param[in] self The handle
- * @param[in] name The property by name
- * @returns The property index of the newly registered property
- *
- */
-Dali::Property::Index RegisterProperty(Dali::Handle& self, const std::string& name, const Dali::Property::Value& propertyValue);
-
-/**
- * Registers an animated property
- *
- * @param[in] self The handle
- * @param[in] name The property by name
- * @returns The property index of the newly registered property
- *
- */
-Dali::Property::Index RegisterAnimatedProperty(Dali::Handle& self, const std::string& name, const Dali::Property::Value& propertyValue);
-
-/**
- * Gets Dali type info
- *
- * @param[in] self The handle
- * @returns The type info
- *
- */
-Dali::TypeInfo GetTypeInfo(Dali::Handle& self);
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "image-wrapper.h"
-
-// EXTERNAL INCLUDES
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-Dali::BufferImage BufferImageNew(const std::string& data, unsigned int width, unsigned int height, Dali::Pixel::Format pixelFormat)
-{
- Dali::BufferImage b = Dali::BufferImage::New( width, height, pixelFormat );
-
- const Dali::PixelBuffer* from = reinterpret_cast<const Dali::PixelBuffer*>( data.c_str() );
- Dali::PixelBuffer* to = b.GetBuffer();
-
- unsigned int len = std::min( width * height * GetBytesPerPixel(pixelFormat), data.size() );
- for(int i = 0; i < len; i++)
- {
- *to++ = *from++;
- }
- return b;
-}
-
-Dali::EncodedBufferImage EncodedBufferImageNew(const std::string& data)
-{
- const uint8_t* const ptr = reinterpret_cast<const uint8_t * const>(data.c_str());
- return Dali::EncodedBufferImage::New(ptr, data.size());
-}
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_IMAGE_WRAPPER_H__
-#define __DALI_IMAGE_WRAPPER_H__
-
-/*
- * Copyright (c) 2015 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/dali-core.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/bind.h"
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Creates a new buffer image from raw data
- *
- * @param[in] data The image byte data
- * @param[in] width The width of the image
- * @param[in] height The height of the image
- * @param[in] pixelFormat The pixel format
- *
- * @returns A Dali BufferImage
- */
-Dali::BufferImage BufferImageNew(const std::string& data, unsigned int width, unsigned int height, Dali::Pixel::Format pixelFormat);
-
-/**
- * Gets an encoded buffer from encoded data
- *
- * @param[in] data The image data
- *
- * @returns A Dali EncodedBufferImage
- *
- */
-Dali::EncodedBufferImage EncodedBufferImageNew(const std::string& data);
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-#ifndef DALI_PROPERTYBUFFER_WRAPPER_H
-#define DALI_PROPERTYBUFFER_WRAPPER_H
-
-/*
- * Copyright (c) 2016 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/dali-core.h>
-#include <dali/public-api/rendering/property-buffer.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/val.h"
-#include "emscripten/bind.h"
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Sets a property buffer from raw data
- *
- * @param[in] self The PropertyBuffer
- * @param[in] data The raw byte data
- *
- */
-void SetPropertyBufferDataRaw(Dali::PropertyBuffer& self, const std::string& data, std::size_t size );
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // DALI_PROPERTYBUFFER_WRAPPER_H
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "property-value-wrapper.h"
-
-// EXTERNAL INCLUDES
-#include <sstream>
-#include <cassert>
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-void RecursiveSetProperty(Dali::Property::Value& propertyValue, const emscripten::val& fromVal)
-{
- static const std::string number("number"); // we could maybe just check the first three chars? (avoiding null ...if that's returned)
- const std::string fromType( fromVal.typeof().as<std::string>() );
-
- if( fromType == "object" )
- {
- // hasOwnProperty is the only way I can find to tell if the object is an array
- // (keys in HasKey returns the JS keys "0","1","2","3",...)
- if( fromVal.hasOwnProperty("length") )
- {
- int length = fromVal["length"].as<int>();
- // we can't tell if what the user of the property value wants with a JS Array
- // by default 'standard' length arrays are always interpreted as Vector2/3/4 etc
- // If the user specifically wants an array they must recast.
- bool isArray = false; // nested ie [ [1,2,3], [4,5,6] ]
- if( 4 == length )
- {
- if( number == fromVal["0"].typeof().as<std::string>() &&
- number == fromVal["1"].typeof().as<std::string>() &&
- number == fromVal["2"].typeof().as<std::string>() &&
- number == fromVal["3"].typeof().as<std::string>() )
- {
- propertyValue = Dali::Vector4( fromVal["0"].as<float>(),
- fromVal["1"].as<float>(),
- fromVal["2"].as<float>(),
- fromVal["3"].as<float>() );
- }
- else
- {
- isArray = true;
- }
- }
- else if( 3 == length )
- {
- if( number == fromVal["0"].typeof().as<std::string>() &&
- number == fromVal["1"].typeof().as<std::string>() &&
- number == fromVal["2"].typeof().as<std::string>() )
- {
- propertyValue = Dali::Vector3( fromVal["0"].as<float>(),
- fromVal["1"].as<float>(),
- fromVal["2"].as<float>() );
- }
- else
- {
- isArray = true;
- }
- }
- else if( 2 == length )
- {
- if( number == fromVal["0"].typeof().as<std::string>() &&
- number == fromVal["1"].typeof().as<std::string>() )
- {
- propertyValue = Dali::Vector2( fromVal["0"].as<float>(),
- fromVal["1"].as<float>() );
- }
- else
- {
- isArray = true;
- }
- }
- else
- {
- isArray = true;
- }
-
- if( isArray )
- {
- propertyValue = Dali::Property::Value(Dali::Property::ARRAY);
- Dali::Property::Array* array = propertyValue.GetArray();
- for( int j = 0; j < length; ++j )
- {
- Dali::Property::Value add;
- array->PushBack( add );
-
- std::stringstream ss;
- ss << j;
-
- emscripten::val val = fromVal[ ss.str() ];
- RecursiveSetProperty( array->GetElementAt(j), val );
- }
- }
- }
- else
- {
- propertyValue = Dali::Property::Value(Dali::Property::MAP);
- Dali::Property::Map* map = propertyValue.GetMap();
- emscripten::val keys = emscripten::val::global("Object").call<emscripten::val>("keys", fromVal);
- int keyLength = keys["length"].as<int>();
- for( int j = 0; j < keyLength; ++j )
- {
- Dali::Property::Value add;
- std::string key = keys[j].as<std::string>();
- (*map)[key] = add;
- emscripten::val keyVal = fromVal[ key ];
- RecursiveSetProperty( *(map->Find( key )), keyVal );
- }
- }
- }
- else if( fromType == "number" )
- {
- propertyValue = Dali::Property::Value( fromVal.as<float>() );
- }
- else if( fromType == "string" )
- {
- propertyValue = Dali::Property::Value( fromVal.as<std::string>() );
- }
- else
- {
- assert(0);
- }
-
-}
-
-emscripten::val JavascriptValue( const Dali::Property::Value& v )
-{
- switch( v.GetType() )
- {
- case Dali::Property::BOOLEAN:
- {
- return emscripten::val(v.Get<bool>());
- break;
- }
- case Dali::Property::FLOAT:
- {
- return emscripten::val(v.Get<float>());
- break;
- }
- case Dali::Property::INTEGER:
- {
- return emscripten::val(v.Get<int>());
- break;
- }
- case Dali::Property::VECTOR2:
- {
- Dali::Vector2 in = v.Get<Dali::Vector2>();
- emscripten::val out = emscripten::val::array();
- out.set("0", emscripten::val(in.x) );
- out.set("1", emscripten::val(in.y) );
- return out;
- break;
- }
- case Dali::Property::VECTOR3:
- {
- Dali::Vector3 in = v.Get<Dali::Vector3>();
- emscripten::val out = emscripten::val::array();
- out.set("0", emscripten::val(in.x) );
- out.set("1", emscripten::val(in.y) );
- out.set("2", emscripten::val(in.z) );
- return out;
- break;
- }
- case Dali::Property::VECTOR4:
- {
- Dali::Vector4 in = v.Get<Dali::Vector4>();
- emscripten::val out = emscripten::val::array();
- out.set("0", emscripten::val(in.x) );
- out.set("1", emscripten::val(in.y) );
- out.set("2", emscripten::val(in.z) );
- out.set("3", emscripten::val(in.w) );
- return out;
- break;
- }
- case Dali::Property::MATRIX3:
- {
- emscripten::val val = emscripten::val::array();
- Dali::Matrix3 mat3 = v.Get<Dali::Matrix3>();
-
- for( int i = 0; i < 9; ++i )
- {
- std::stringstream key;
- key << i;
- val.set( key.str(), emscripten::val(mat3.AsFloat()[i]) );
- }
- return val;
- break;
- }
- case Dali::Property::MATRIX:
- {
- emscripten::val val = emscripten::val::array();
- Dali::Matrix mat = v.Get<Dali::Matrix>();
-
- for( int i = 0; i < 16; ++i )
- {
- std::stringstream key;
- key << i;
- val.set( key.str(), emscripten::val(mat.AsFloat()[i]) );
- }
- return val;
- break;
- }
- case Dali::Property::RECTANGLE:
- {
- Dali::Rect<int> in = v.Get<Dali::Rect<int> >();
- emscripten::val out = emscripten::val::array();
- out.set("0", emscripten::val(in.x) );
- out.set("1", emscripten::val(in.y) );
- out.set("2", emscripten::val(in.width) );
- out.set("3", emscripten::val(in.height) );
- return out;
- break;
- }
- case Dali::Property::ROTATION:
- {
- Dali::Quaternion in = v.Get<Dali::Quaternion>();
- emscripten::val out = emscripten::val::array();
- Dali::Vector3 axis;
- Dali::Radian angle;
- in.ToAxisAngle(axis, angle);
-
- out.set("0", emscripten::val( axis.x ) );
- out.set("1", emscripten::val( axis.y ) );
- out.set("2", emscripten::val( axis.z ) );
- out.set("3", emscripten::val( Dali::Degree(angle).degree ) );
-
- return out;
- break;
- }
- case Dali::Property::STRING:
- {
- return emscripten::val( v.Get<std::string>() );
- break;
- }
- case Dali::Property::ARRAY:
- {
- emscripten::val val = emscripten::val::array();
- Dali::Property::Array *array = v.GetArray();
- DALI_ASSERT_ALWAYS(array);
-
- for( int i = 0; i < array->Count(); ++i )
- {
- Dali::Property::Value& property = array->GetElementAt( i );
- std::stringstream key;
- key << i;
- val.set( key.str(), JavascriptValue( property ) );
- }
-
- return val;
- break;
- }
- case Dali::Property::MAP:
- {
- emscripten::val val = emscripten::val::object();
- Dali::Property::Map *map = v.GetMap();
- DALI_ASSERT_ALWAYS(map);
-
- for( int i = 0; i < map->Count(); ++i )
- {
- std::string key;
- StringValuePair pair = map->GetPair(i);
- val.set( pair.first, JavascriptValue( pair.second ) );
- }
-
- return val;
- break;
- }
- case Dali::Property::NONE:
- {
- break;
- }
- } // switch type
-
- return emscripten::val::undefined();
-
-}
-
-Dali::Property::Value PropertyMapGet( Dali::Property::Map& self, const std::string& key)
-{
- Dali::Property::Value ret;
-
- Dali::Property::Value* v = self.Find(key);
-
- if(v)
- {
- ret = *v;
- }
-
- return ret;
-}
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_PROPERTY_VALUE_WRAPPER_H__
-#define __DALI_PROPERTY_VALUE_WRAPPER_H__
-
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-#include <dali/public-api/dali-core.h>
-#include "emscripten/val.h"
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Sets a property value From an Emscripten value. Recursively for Maps and Arrays
- *
- * @param[in] propertyValue The property value to set
- * @param[in] fromVal The emscripten value to set from
- *
- */
-void RecursiveSetProperty(Dali::Property::Value& propertyValue, const emscripten::val& fromVal);
-
-/**
- * Set an Emscripten value from a Dali property Value
- *
- * @param[in] value The Dali Property value
- *
- * @returns The Emscripten value
- *
- */
-emscripten::val JavascriptValue( const Dali::Property::Value& value );
-
-/**
- * Gets a Dali value from a Dali Property Map
- *
- * @param[in] self The property map
- * @param[in] key The key of the value to fetch
- *
- * @returns The property value
- *
- */
-Dali::Property::Value PropertyMapGet( Dali::Property::Map& self, const std::string& key );
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "render-task-wrapper.h"
-
-// EXTERNAL INCLUDES
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-Dali::Vector2 ScreenToLocal(Dali::RenderTask self, Dali::Actor actor, float screenX, float screenY)
-{
- float localX = 0;
- float localY = 0;
- self.ViewportToLocal(actor, screenX, screenY, localX, localY);
- return Dali::Vector2(localX,localY);
-}
-
-Dali::Vector2 WorldToScreen(Dali::RenderTask self, const Dali::Vector3 &position)
-{
- float screenX = 0;
- float screenY = 0;
- self.WorldToViewport(position, screenX, screenY);
- return Dali::Vector2(screenX, screenY);
-}
-
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_RENDER_TASK_WRAPPER_H__
-#define __DALI_RENDER_TASK_WRAPPER_H__
-
-/*
- * Copyright (c) 2015 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/dali-core.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/bind.h"
-
-// INTERNAL INCLUDES
-#include "actor-wrapper.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Gets the local coordinates from the screen coordinates
- *
- * @param[in] self The render task
- * @param[in] actor The Dali actor
- * @param[in] screenX The screen X position
- * @param[in] screenY The screen Y position
- *
- * @returns The Local coordinates
- *
- */
-Dali::Vector2 ScreenToLocal(Dali::RenderTask self, Dali::Actor actor, float screenX, float screenY);
-
-/**
- * Gets the screen coordinates from a position
- *
- * @param[in] self The RenderTask
- * @param[in] position The position
- *
- * @returns The screen coordinates of the actor
- *
- */
-Dali::Vector2 WorldToScreen(Dali::RenderTask self, const Dali::Vector3 &position);
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-#ifndef DALI_SIGNAL_HOLDER_H
-#define DALI_SIGNAL_HOLDER_H
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-struct BaseSignalSlot : public Dali::ConnectionTracker
-{
-};
-
-/**
- * A wrapper class to let JS hold Signals
- */
-class SignalHolder : public Dali::ConnectionTracker
-{
-public:
- typedef Dali::Vector<BaseSignalSlot*> Slots;
- Slots mSlots;
- SignalHolder() {}
-
- ~SignalHolder()
- {
- for(Slots::Iterator iter = mSlots.Begin(); iter != mSlots.End(); ++iter)
- {
- delete *iter;
- }
- }
-
- /*
- * Adds a base signal to the list of slots
- */
- void add(BaseSignalSlot* s) { mSlots.PushBack(s); }
-
-private:
- SignalHolder(const SignalHolder& nocopy);
- SignalHolder& operator=(const SignalHolder& noassign);
-};
-
-
-}; // Emscripten
-}; // Internal
-}; // Dali
-
-
-#endif // header
+++ /dev/null
-Dali Browser Regression Tests
------------------------------
-
-These tests work with a web server but not from the filesystem (a "file:///" URI).
-
-To run the tests locally run a local web server.
-
-One quick way to do this if you have nodeJS and npm installed is
-
-npm install http-server -g
-
-then in the directory with dali_tests.html run
-
-http-server
-
-or
-
-http-server -p:8888
-
-if you already have a local server running on 8080.
-
-Note: Alternatively you can use python with
-
-python -m SimpleHTTPServer 8080
-
+++ /dev/null
-<html>
-
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width">
- <title>DALi Browser Wrapper Regression Tests</title>
- <link rel="stylesheet" href="qunit-1.21.0.css">
- <link rel="stylesheet" href="dali-tests.css" type="text/css" media="screen"/>
-
- </head>
-
- <body style="background-color: #fff;width:700px">
- <script src="qunit-1.21.0.js"></script>
- <script type="text/javascript" src="./utilities.js"></script>
- <script type="text/javascript" src="./properties.js"></script>
- <script type="text/javascript" src="./geometry.js"></script>
- <script type="text/javascript" src="./signals.js"></script>
- <script type="text/javascript" src="./math.js"></script>
- <script type="text/javascript" src="./animation.js"></script>
- <script type="text/javascript" src="./shaders.js"></script>
- <script type="text/javascript" src="./views.js"></script>
-
- <div id="qunit"></div>
- <iframe id="daliframe" scrolling="no" width="600px" border="1px solid" ></iframe>
-
- <img alt="Brand" width="50" id="testImage" style="visibility: hidden" src="data:image/png;base64,/9j/4QCGRXhpZgAASUkqAAgAAAABAJiCAgBiAAAAGgAAAAAAAABDb3B5cmlnaHQgKGMpIDIwMTQgU2Ftc3VuZyBFbGVjdHJvbmljcywgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMDogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wAAAA/+EC12h0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAtRXhpdjIiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtcDpDcmVhdG9yVG9vbD0iS2lwaS1wbHVnaW5zLTIuNS4wIgogICB0aWZmOlNvZnR3YXJlPSJLaXBpLXBsdWdpbnMtMi41LjAiPgogICA8ZGM6cmlnaHRzPgogICAgPHJkZjpBbHQ+CiAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ij5Db3B5cmlnaHQgKGMpIDIwMTQgU2Ftc3VuZyBFbGVjdHJvbmljcywgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMDogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wPC9yZGY6bGk+CiAgICA8L3JkZjpBbHQ+CiAgIDwvZGM6cmlnaHRzPgogIDwvcmRmOkRlc2NyaXB0aW9uPgogPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K/+0ArlBob3Rv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">
-
- </body>
-
-</html>
+++ /dev/null
-
-QUnit.module("Animation", {
- setup : function() {
- QUnit.stop();
- var that = this;
- this.cb = function(e) {
- QUnit.ok(true, "Scene loaded");
- var iframe = document.getElementById('daliframe');
- that.doc = iframe.contentDocument || iframe.contentWindow.document;
- that.doc.Module.postDaliWrapperRun = function() {
- dali = that.doc.Module;
- QUnit.start();
- };
- };
- loadDocument("dali-page.html"+window.location.search, this.cb);
- },
- teardown : function() {
- var v = document.getElementById("daliframe");
- v.removeEventListener("load", this.cb, true);
- }
-});
-
-QUnit.test( "spline path", function( assert ) {
-
- var done1 = assert.async();
-
- threeSquares();
- var col = {};
- collectByName(col);
- var actor = col.red;
-
- var a = new dali.Animation(0);
- var path = new dali.Path();
-
- path.points = [
- [-150, -50, 0],
- [0.0, 70.0, 0.0],
- [190.0, -150.0, 0.0]
- ];
-
- assert.ok(compareArrays(path.points, [
- [-150, -50, 0],
- [0.0, 70.0, 0.0],
- [190.0, -150.0, 0.0]
- ]));
-
- dali.generateControlPoints(path, 0.35);
-
- assert.ok(compareArrays(path.controlPoints, [
- [-97.5, -8, 0],
- [-66.94940948486328, 76.16658020019531, 0],
- [101.31224060058594, 60.66832733154297, 0],
- [123.5, -73, 0]
- ]));
-
- a.setDuration(0.1);
- a.animatePath(actor, path, [1, 0, 0], dali.AlphaFunction.LINEAR, 0, 0.1);
- a.play();
-
-
- function checkPos() {
- assert.ok(actor.position = path.points[2]);
- clear();
- actor.delete();
- path.delete();
- a.delete();
- done1();
- }
-
- window.setTimeout(checkPos, 200);
-
-});
-
-QUnit.test( "linear", function( assert ) {
-
- var done1 = assert.async();
- var done2 = assert.async();
- var done3 = assert.async();
-
- threeSquares();
- var col = {};
- collectByName(col);
- var actor = col.red;
-
- var a = new dali.Animation(0);
- a.setDuration(0.1);
- a.animateTo(actor, "position", [20, 0, 0], dali.AlphaFunction.LINEAR, 0, 0.1);
- a.play();
-
- function checkAnimateBetween() {
- assert.ok(actor.position = [0, 0, -30]);
- clear();
- a.delete();
- actor.delete();
- done3();
- }
-
- function checkAnimateBy() {
- assert.ok(actor.position = [120, 100, 0]);
- a.clear();
- a.animateBetween(actor,
- "position", [ [ 0, [10,20,30] ],
- [ 1.0,[0, 0, -30] ] ],
- "linear",
- 0,
- 0.1,
- "linear");
- a.play();
- window.setTimeout(checkAnimateBetween, 200);
- done2();
- }
-
- function checkAnimateTo() {
- assert.ok(actor.position = [20, 0, 0]);
- actor.position = [100, 100, 0];
-
- a.clear(); // var a = new dali.Animation(0);
- a.setDuration(0.1);
- a.animateBy(actor, "position", [20, 0, 0], dali.AlphaFunction.LINEAR, 0, 0.1);
- a.play();
- window.setTimeout(checkAnimateBy, 200);
- done1();
- }
-
- window.setTimeout(checkAnimateTo, 200);
-
-});
-
+++ /dev/null
-<html><head>
- <title>Dali Browser Wrapper Regression Tests</title>
-
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width">
-
-</head>
-<body style="background-color: #fff;width=600px">
-
- <div class="emscripten" id="status">
- Downloading...
- </div>
-
- <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" width="600" height="800" style="background-color: black;"></canvas>
-
- <script type="text/javascript"> // emscripten
-
- var statusElement = document.getElementById('status');
-
- var Module = {
- doNotCaptureKeyboard:true,
- preRun: [],
- postRun: [],
- print: (function() {
- return function(text) {
- text = Array.prototype.slice.call(arguments).join(' ');
- console.log("STDOUT:", text);
- };
- })(),
- printErr: function(text) {
- text = Array.prototype.slice.call(arguments).join(' ');
- console.error("STDERR:", text);
- },
- canvas: document.getElementById('canvas'),
- setStatus: function(text) {
- if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
- if (text === Module.setStatus.text) return;
- statusElement.innerHTML = text;
- },
- totalDependencies: 0,
- monitorRunDependencies: function(left) {
- this.totalDependencies = Math.max(this.totalDependencies, left);
- Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
- },
-
- postRun: function () {
- // postRun; so that dali-emscripten.js is loaded first
- // (postMainLoop to run all the time)
- var s = document.createElement("script");
- s.src = "dali-wrapper.js";
- document.body.appendChild(s);
- Module.setStatus("Loading: dali-wrapper.js");
- },
-
- loadScriptFile: function(name) {
- var chainLoadScript = document.createElement("script");
- chainLoadScript.src = name;
- document.body.appendChild(chainLoadScript);
- Module.setStatus("Loading: " + name);
- },
-
- postDaliWrapperRun: function () {
- //
- // chain load main.js
- //
-
- // ** todo run the tests?? ... in geometry.js callback
- //
- document.dali = dali;
- },
-
- // This function is here as putting it in utilities.js caused the BufferImage() ctor to fail.
- // The ctor uses 'instanceof' to check for string/uint8array and converts if needed to copy binary
- // data into Dali. Apparently 'instanceof' in Javascript can lie if the data is coming from a
- // different frame. I think(!) this is why 'uint8array instanceof Uint8array' succeded outside the ctor
- // call, but once inside the ctor 'arguments[0] instanceof Uint8array' failed and the ctor didn't
- // pick the correct conversion function. ....don't we love Javascript.
- // tldr; If the function is here then we can use it.
- unitTestEmbeddedImage: function () {
- "use strict";
- // name is presumed to be in the html as base64 data
- // (from the iframe document)
- // var iframe = document.getElementById('daliframe');
- var doc = document; // iframe.contentDocument || iframe.contentWindow.document;
- var c = doc.createElement("canvas");
- var img = doc.getElementById("testImage");
- c.width = img.naturalWidth;
- c.height = img.naturalHeight;
- var context = c.getContext("2d");
- context.drawImage(img, 0, 0 );
- var imageData = context.getImageData(0, 0, img.naturalWidth, img.naturalHeight); // <-ImageData
- var uint8clampedarray = new Uint8ClampedArray(imageData.data);
- var uint8array = new Uint8Array(uint8clampedarray);
- var image = new dali.BufferImage(uint8array, imageData.width, imageData.height, dali.PixelFormat.RGBA8888);
- return image;
- }
-
- }; // Module
-
- document.Module = Module;
-
- </script>
-
- <script async type="text/javascript" src="dali-emscripten.js"></script>
-
- <img alt="Brand" width="50" id="testImage" style="visibility: hidden" src="data:image/png;base64,/9j/4QCGRXhpZgAASUkqAAgAAAABAJiCAgBiAAAAGgAAAAAAAABDb3B5cmlnaHQgKGMpIDIwMTQgU2Ftc3VuZyBFbGVjdHJvbmljcywgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMDogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wAAAA/+EC12h0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAtRXhpdjIiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtcDpDcmVhdG9yVG9vbD0iS2lwaS1wbHVnaW5zLTIuNS4wIgogICB0aWZmOlNvZnR3YXJlPSJLaXBpLXBsdWdpbnMtMi41LjAiPgogICA8ZGM6cmlnaHRzPgogICAgPHJkZjpBbHQ+CiAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ij5Db3B5cmlnaHQgKGMpIDIwMTQgU2Ftc3VuZyBFbGVjdHJvbmljcywgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMDogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wPC9yZGY6bGk+CiAgICA8L3JkZjpBbHQ+CiAgIDwvZGM6cmlnaHRzPgogIDwvcmRmOkRlc2NyaXB0aW9uPgogPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K/+0ArlBob3Rv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">
-
-</body>
-</html>
-
+++ /dev/null
-div#overall {
- padding-right: 550px;
-}
-
-iframe#daliframe {
- position: fixed;
- top: 2px;
- right: 2px;
- border: 1px solid;
- width: 604px;
- height: 800px;
-}
-
-#daliframe.qunit-pass {
- border-color: #C6E746;
-}
-#daliframe.qunit-fail {
- border-color: #EE5757;
-}
\ No newline at end of file
+++ /dev/null
-<html>
- <head>
- <meta charset="UTF-8"/>
- <title>DALi Browser API Regression Tests</title>
- <link rel="stylesheet" href="qunit-1.21.0.css" type="text/css" media="screen"/>
-
- </head>
- <body>
- <h1 id="qunit-header">DALi Browser Test Suite</h1>
-
- <div id="qunit-testrunner-toolbar"></div>
-
- <h2 id="qunit-userAgent">All</h2>
- <ol id="qunit-testresult">
- <li><a href="all.html">All</a></li>
- </ol>
- <h2 id="qunit-userAgent">Browser API</h2>
- <ol id="qunit-testresult">
- <li><a href="all.html?filter=Properties">Properties</a></li>
- <li><a href="all.html?filter=Geometry">Geometry</a></li>
- <li><a href="all.html?filter=Signals">Signals</a></li>
- <li><a href="all.html?filter=Math">Math</a></li>
- <li><a href="all.html?filter=Animation">Animation</a></li>
- <li><a href="all.html?filter=Shaders">Shaders</a></li>
- <li><a href="all.html?filter=Views">Views</a></li>
- </ol>
-
- </body>
-</html>
+++ /dev/null
-
-QUnit.module("Geometry", {
- setup : function() {
- QUnit.stop();
- var that = this;
- this.cb = function(e) {
- QUnit.ok(true, "Scene loaded");
- var iframe = document.getElementById('daliframe');
- that.doc = iframe.contentDocument || iframe.contentWindow.document;
- that.doc.Module.postDaliWrapperRun = function() {
- dali = that.doc.Module;
- QUnit.start();
- };
- };
- loadDocument("dali-page.html"+window.location.search, this.cb);
- },
- teardown : function() {
- var v = document.getElementById("daliframe");
- v.removeEventListener("load", this.cb, true);
- }
-});
-
-
-QUnit.test( "colour quad", function( assert ) {
- var halfQuadSize = 0.5;
-
- // using helper function to create property buffer
- var verts = dali.createPropertyBuffer( {format: [ ["aPosition", dali.PropertyType.VECTOR3],
- ["aCol", dali.PropertyType.VECTOR4] ],
- data: { "aPosition": [ [-halfQuadSize, -halfQuadSize, 0.0],
- [+halfQuadSize, -halfQuadSize, 0.0],
- [-halfQuadSize, +halfQuadSize, 0.0],
- [+halfQuadSize, +halfQuadSize, 0.0]
- ],
- "aCol": [ [0, 0, 0, 1],
- [1, 0, 1, 1],
- [0, 1, 0, 1],
- [1, 1, 1, 1]
- ]
- }
- });
-
- var indices = dali.createPropertyBuffer( { format: [ ["indices", dali.PropertyType.INTEGER]],
- data: { "indices": [0, 3, 1, 0, 2, 3] } } ) ;
-
- var geometry = new dali.Geometry();
-
- assert.ok(verts);
- assert.ok(indices);
- assert.ok(geometry);
-
- geometry.addVertexBuffer(verts);
- geometry.setIndexBuffer(indices);
-
- var vertex = "" +
- "attribute mediump vec3 aPosition;" +
- "attribute mediump vec4 aCol;" +
- "uniform mediump mat4 uMvpMatrix;" +
- "uniform mediump vec3 uSize;" +
- "uniform lowp vec4 uColor;" +
- "varying lowp vec4 vColor;" +
- "" +
- "void main()" +
- "{" +
- " vColor = aCol * uColor;" +
- " mediump vec4 vertexPosition = vec4(aPosition,1.0);" +
- " vertexPosition.xyz *= uSize;" +
- " gl_Position = uMvpMatrix * vertexPosition;" +
- "}";
-
- var fragment = "" +
- "varying lowp vec4 vColor;" +
- "uniform lowp vec4 uColor;" +
- "" +
- "void main()" +
- "{" +
- " gl_FragColor = vColor * uColor;" +
- "}";
-
- var shader = new dali.Shader(vertex, fragment, dali.ShaderHints.HINT_NONE);
- assert.ok(shader);
-
- var material = new dali.Material(shader);
- assert.ok(material);
-
- var renderer = new dali.Renderer(geometry, material);
- assert.ok(renderer);
-
- var actor = new dali.Actor();
- assert.ok(actor);
-
- actor.addRenderer(renderer);
-
- dali.stage.add(actor);
-
- actor.parentOrigin = [0.5, 0.5, 0.0];
- actor.size = [100,100,1];
-
-});
-
-
-QUnit.test( "textured quad", function( assert ) {
-
- var halfQuadSize = 0.5;
-
- // using helper function to create property buffer
- var verts = dali.createPropertyBuffer( {format: [ ["aPosition", dali.PropertyType.VECTOR3],
- ["aTexCoord", dali.PropertyType.VECTOR2] ],
- data: { "aPosition": [ [-halfQuadSize, -halfQuadSize, 0.0],
- [+halfQuadSize, -halfQuadSize, 0.0],
- [-halfQuadSize, +halfQuadSize, 0.0],
- [+halfQuadSize, +halfQuadSize, 0.0]
- ],
- "aTexCoord": [ [0, 0],
- [1, 0],
- [0, 1],
- [1, 1]
- ]
- }
- });
-
- var indices = dali.createPropertyBuffer( { format: [ ["indices", dali.PropertyType.INTEGER]],
- data: { "indices": [0, 3, 1, 0, 2, 3] } } ) ;
-
- var geometry = new dali.Geometry();
-
- assert.ok(verts);
- assert.ok(indices);
- assert.ok(geometry);
-
- geometry.addVertexBuffer(verts);
- geometry.setIndexBuffer(indices);
-
- var vertex = "" +
- "// atributes\n" +
- "attribute mediump vec3 aPosition;" +
- "attribute mediump vec2 aTexCoord;\n" +
- "// inbuilt\n" +
- "uniform mediump mat4 uMvpMatrix;" +
- "uniform mediump vec3 uSize;" +
- "uniform lowp vec4 uColor;" +
- "// varying\n" +
- "varying mediump vec2 vTexCoord;\n" +
- "" +
- "void main()" +
- "{" +
- " mediump vec4 vertexPosition = vec4(aPosition, 1.0);" +
- " vertexPosition.xyz *= uSize;" +
- " gl_Position = uMvpMatrix * vertexPosition;" +
- " vTexCoord = aTexCoord;\n" +
- "}";
-
- var fragment = "" +
- "uniform lowp vec4 uColor;" +
- "uniform sampler2D sTexture;\n" +
- "varying mediump vec2 vTexCoord;\n" +
- "\n" +
- "void main()" +
- "{" +
- " gl_FragColor = texture2D(sTexture, vTexCoord) * uColor;\n" +
- "}";
-
-
- var shader = new dali.Shader(vertex, fragment, dali.ShaderHints.HINT_NONE);
- assert.ok(shader);
-
- var material = new dali.Material(shader);
- assert.ok(material);
-
- var image = dali.unitTestEmbeddedImage() ;
- assert.ok(image);
- var sampler = new dali.Sampler();
- material.addTexture(image, "sTexture", sampler);
-
- var renderer = new dali.Renderer(geometry, material);
- assert.ok(renderer);
-
- var actor = new dali.Actor();
-
- actor.addRenderer(renderer);
-
- dali.stage.add(actor);
-
- actor.parentOrigin = [0.5, 0.5, 0.0];
- actor.size = [100,100,1];
-
-});
+++ /dev/null
-function assertArray(assert, a, b, epsilon) {
- assert.ok(a.length === b.length);
- for (var i = 0, len = a.length; i < len; ++i) {
- assert.ok(a[i] > b[i] - epsilon && a[i] < b[i] + epsilon);
- }
-}
-
-QUnit.module("Math", {
- setup : function() {
- QUnit.stop();
- var that = this;
- this.cb = function(e) {
- QUnit.ok(true, "Scene loaded");
- var iframe = document.getElementById('daliframe');
- that.doc = iframe.contentDocument || iframe.contentWindow.document;
- that.doc.Module.postDaliWrapperRun = function() {
- dali = that.doc.Module;
- QUnit.start();
- };
- };
- loadDocument("dali-page.html"+window.location.search, this.cb);
- },
- teardown : function() {
- var v = document.getElementById("daliframe");
- v.removeEventListener("load", this.cb, true);
- }
-});
-
-QUnit.test( "vector", function( assert ) {
- assert.ok(dali.vectorLength([1, 2, 3, 4]) === Math.sqrt(1 * 1 + 2 * 2 + 3 * 3));
- assert.ok(dali.vectorLengthSquared(dali.normalize([0, 0, 0, 1])) === 0);
-
- var f = 2;
- assert.ok(1 === dali.vectorLengthSquared(dali.normalize([Math.cos(f) * 10.0,
- Math.cos(f + 1.0) * 10.0,
- Math.cos(f + 2.0) * 10.0,
- 1.0
- ])));
- assertArray(assert, dali.vectorCross([0, 1, 0], [0, 0, 1]), [1, 0, 0], 0.001);
-
- assertArray(assert, dali.vectorAdd([1, 2, 3], [2, 3, 4], [1, 1, 1]), [4, 6, 8], 0.001);
-
-});
-
-
-QUnit.test( "quaternion", function( assert ) {
-
- assertArray(assert, dali.axisAngleToQuaternion([1.0, 2.0, 3.0, Math.PI / 3.0, Math.PI / 2.0]), [0.189, 0.378, 0.567, 0.707], 0.001);
-
- assertArray(assert, dali.quaternionToAxisAngle([1.1, 3.4, 2.7, 0.932]), [3.03, 9.38, 7.45, 0.74],
- 0.01);
-
- var mq = dali.vectorAdd(dali.vectorCross([0.045, 0.443, 0.432], [0.612, 0.344, -0.144]),
- dali.vectorByScalar([0.612, 0.344, -0.144], 0.784),
- dali.vectorByScalar([0.045, 0.443, 0.432], 0.697));
-
- assertArray(assert, dali.quatByQuat([0.045, 0.443, 0.432, 0.784], [0.612, 0.344, -0.144, 0.697]), [mq[0], mq[1], mq[2], (0.784 * 0.697) - dali.vectorDot([0.045, 0.443, 0.432], [0.612, 0.344, -0.144])],
- 0.001);
-
-});
+++ /dev/null
-
-QUnit.module("Properties", {
- setup : function() {
- QUnit.stop();
- var that = this;
- this.cb = function(e) {
- QUnit.ok(true, "Scene loaded");
- var iframe = document.getElementById('daliframe');
- that.doc = iframe.contentDocument || iframe.contentWindow.document;
- that.doc.Module.postDaliWrapperRun = function() {
- dali = that.doc.Module;
- QUnit.start();
- };
- };
- loadDocument("dali-page.html"+window.location.search, this.cb);
- },
- teardown : function() {
- var v = document.getElementById("daliframe");
- v.removeEventListener("load", this.cb, true);
- }
-});
-
-QUnit.test( "dotted property access", function( assert ) {
-
- var actor = new dali.Actor();
-
- assert.ok( "" === actor.name );
- assert.ok( compareArrays(actor.position, [0, 0, 0]) );
- assert.ok( compareArrays(actor.parentOrigin, [0, 0, 0.5]) );
-
-});
-
-QUnit.test( "hierarchy", function( assert ) {
-
- var actor = new dali.Actor();
- actor.parentOrigin = [0.5, 0.5, 0.5];
- actor.anchorPoint = [0.5, 0.5, 0.5];
- actor.text = "actor";
- actor.name = actor.text;
- actor.size = [100, 100, 1];
- actor.position = [0, 0, 10];
- dali.stage.add(actor);
-
- var hello = new dali.Actor();
- hello.text = "hello";
- hello.name = hello.text;
- actor.add(hello);
-
- var hellochild = new dali.Actor();
- hellochild.text = "hello-child";
- hellochild.name = hellochild.text;
- hello.add(hellochild);
-
- var hellochild2 = new dali.Actor();
- hellochild2.text = "hello-child2";
- hellochild2.name = hellochild2.text;
- hello.add(hellochild2);
-
- var hellochildchild = new dali.Actor();
- hellochildchild.text = "hello-child-child1";
- hellochildchild.name = "hello-child-child1";
- hellochildchild.name = hellochildchild.text;
- hellochild.add(hellochildchild);
-
-
- var depthfirst = actor.findAllChildren();
-
- assert.ok(actor.getChildCount() === 1);
-
- var directChildren = actor.directChildren();
-
- assert.ok(directChildren.length === 1);
- assert.ok(directChildren[0].getId() === hello.getId());
-
- actor.position = [100, 100, 0];
-
- var root = dali.stage.getRootLayer(); //rootRotationActor;
-
- actor.remove(hello);
- assert.ok(actor.getChildCount() === 0);
-
- actor.add(hello);
- assert.ok(actor.getChildCount() === 1);
-
- var rootLayerCount = root.getChildCount();
- dali.stage.remove(actor); // check these don't assert
- assert.ok(root.getChildCount() === rootLayerCount - 1);
-
- dali.stage.add(actor);
- assert.ok(root.getChildCount() === rootLayerCount);
-
- assert.ok(root.findChildByName("none") === null);
-
-});
-
-QUnit.test( "register property", function( assert ) {
- var s = dali.stage;
- var root = s.getRootLayer(); //rootRotationActor;
-
- var another = new dali.Actor();
- another.parentOrigin = [0.5, 0.5, 0.5];
- another.anchorPoint = [0.5, 0.5, 0.5];
- another.text = "peppa";
- another.name = another.text;
- another.size = [100, 100, 1];
- another.position = [-50, 100, 0];
- root.add(another);
-
- var c = root.getChildAt(root.getChildCount() - 1);
- //var n = c.getChildCount();
- var p = c.getParent();
- assert.ok(p.getId() == root.getId());
-
- var matrix = c.worldMatrix;
-
- assert.ok(matrix.length === 16);
-
-});
-
-QUnit.test( "get/set", function( assert ) {
- var s = dali.stage;
- threeSquares();
- var col = {};
- collectByName(col);
- var actor = col.red;
- var p = actor.position;
- actor.position = [1, 1, 1];
- assert.ok(compareArrays(actor.position, [1, 1, 1]));
- actor.position = [3, 3, 3];
- assert.ok(compareArrays(actor.position, [3, 3, 3]));
- actor.position = p;
-});
+++ /dev/null
-/*!
- * QUnit 1.21.0
- * https://qunitjs.com/
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license
- * https://jquery.org/license
- *
- * Date: 2016-02-01T13:07Z
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699A4;
- background-color: #0D3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: 400;
-
- border-radius: 5px 5px 0 0;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #C2CCD1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #FFF;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 0.5em 0 0.1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 1em 0.5em 1em;
- color: #5E740B;
- background-color: #EEE;
- overflow: hidden;
-}
-
-#qunit-filteredTest {
- padding: 0.5em 1em 0.5em 1em;
- background-color: #F4FF77;
- color: #366097;
-}
-
-#qunit-userAgent {
- padding: 0.5em 1em 0.5em 1em;
- background-color: #2B81AF;
- color: #FFF;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
- padding: 0.2em;
-}
-
-.qunit-url-config {
- display: inline-block;
- padding: 0.1em;
-}
-
-.qunit-filter {
- display: block;
- float: right;
- margin-left: 1em;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 1em 0.4em 1em;
- border-bottom: 1px solid #FFF;
- list-style-position: inside;
-}
-
-#qunit-tests > li {
- display: none;
-}
-
-#qunit-tests li.running,
-#qunit-tests li.pass,
-#qunit-tests li.fail,
-#qunit-tests li.skipped {
- display: list-item;
-}
-
-#qunit-tests.hidepass {
- position: relative;
-}
-
-#qunit-tests.hidepass li.running,
-#qunit-tests.hidepass li.pass {
- visibility: hidden;
- position: absolute;
- width: 0;
- height: 0;
- padding: 0;
- border: 0;
- margin: 0;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li.skipped strong {
- cursor: default;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #C2CCD1;
- text-decoration: none;
-}
-
-#qunit-tests li p a {
- padding: 0.25em;
- color: #6B6464;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #FFF;
-
- border-radius: 5px;
-}
-
-.qunit-source {
- margin: 0.6em 0 0.3em;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: 0.2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 0.5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #E0F2BE;
- color: #374E0C;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #FFCACA;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: #000; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #FFF;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3C510C;
- background-color: #FFF;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #FFF;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
-}
-
-#qunit-tests .fail { color: #000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: #008000; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-/*** Skipped tests */
-
-#qunit-tests .skipped {
- background-color: #EBECE9;
-}
-
-#qunit-tests .qunit-skipped-label {
- background-color: #F4FF77;
- display: inline-block;
- font-style: normal;
- color: #366097;
- line-height: 1.8em;
- padding: 0 0.5em;
- margin: -0.4em 0.4em -0.4em 0;
-}
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 1em 0.5em 1em;
-
- color: #2B81AF;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid #FFF;
-}
-#qunit-testresult .module-name {
- font-weight: 700;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
+++ /dev/null
-/*!
- * QUnit 1.21.0
- * https://qunitjs.com/
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license
- * https://jquery.org/license
- *
- * Date: 2016-02-01T13:07Z
- */
-
-(function( global ) {
-
-var QUnit = {};
-
-var Date = global.Date;
-var now = Date.now || function() {
- return new Date().getTime();
-};
-
-var setTimeout = global.setTimeout;
-var clearTimeout = global.clearTimeout;
-
-// Store a local window from the global to allow direct references.
-var window = global.window;
-
-var defined = {
- document: window && window.document !== undefined,
- setTimeout: setTimeout !== undefined,
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch ( e ) {
- return false;
- }
- }() )
-};
-
-var fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" );
-var globalStartCalled = false;
-var runStarted = false;
-
-var toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty;
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[ i ] === b[ j ] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
-function objectValues ( obj ) {
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[ key ];
- vals[ key ] = val === Object( val ) ? objectValues( val ) : val;
- }
- }
- return vals;
-}
-
-function extend( a, b, undefOnly ) {
- for ( var prop in b ) {
- if ( hasOwn.call( b, prop ) ) {
-
- // Avoid "Member not found" error in IE8 caused by messing with window.constructor
- // This block runs on every environment, so `global` is being used instead of `window`
- // to avoid errors on node.
- if ( prop !== "constructor" || a !== global ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
- } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) {
- a[ prop ] = b[ prop ];
- }
- }
- }
- }
-
- return a;
-}
-
-function objectType( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- }
-
- // Consider: typeof null === object
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ),
- type = match && match[ 1 ];
-
- switch ( type ) {
- case "Number":
- if ( isNaN( obj ) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Set":
- case "Map":
- case "Date":
- case "RegExp":
- case "Function":
- case "Symbol":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
-}
-
-// Safe object type checking
-function is( type, obj ) {
- return QUnit.objectType( obj ) === type;
-}
-
-var getUrlParams = function() {
- var i, current;
- var urlParams = {};
- var location = window.location;
- var params = location.search.slice( 1 ).split( "&" );
- var length = params.length;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
-
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- if ( urlParams[ current[ 0 ] ] ) {
- urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] );
- } else {
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
- }
-
- return urlParams;
-};
-
-// Doesn't support IE6 to IE9, it will return undefined on these browsers
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 4 : offset;
-
- var stack, include, i;
-
- if ( e.stack ) {
- stack = e.stack.split( "\n" );
- if ( /^error$/i.test( stack[ 0 ] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
-
- // Support: Safari <=6 only
- } else if ( e.sourceURL ) {
-
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
-
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-
-function sourceFromStacktrace( offset ) {
- var error = new Error();
-
- // Support: Safari <=7 only, IE <=10 - 11 only
- // Not all browsers generate the `stack` property for `new Error()`, see also #636
- if ( !error.stack ) {
- try {
- throw error;
- } catch ( err ) {
- error = err;
- }
- }
-
- return extractStacktrace( error, offset );
-}
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-var config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // HTML Reporter: collapse every test except the first failing test
- // If false, all failing tests will be expanded
- collapse: true,
-
- // by default, scroll to top of the page when suite is done
- scrolltop: true,
-
- // depth up-to which object will be dumped
- maxDepth: 5,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "hidepassed",
- label: "Hide passed tests",
- tooltip: "Only show tests and assertions that fail. Stored as query-strings."
- },
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the " +
- "global object (`window` in Browsers). Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " +
- "exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: [],
-
- // Stack of nested modules
- moduleStack: [],
-
- // The first unnamed module
- currentModule: {
- name: "",
- tests: []
- },
-
- callbacks: {}
-};
-
-var urlParams = defined.document ? getUrlParams() : {};
-
-// Push a loose unnamed module to the modules collection
-config.modules.push( config.currentModule );
-
-if ( urlParams.filter === true ) {
- delete urlParams.filter;
-}
-
-// String search anywhere in moduleName+testName
-config.filter = urlParams.filter;
-
-config.testId = [];
-if ( urlParams.testId ) {
- // Ensure that urlParams.testId is an array
- urlParams.testId = decodeURIComponent( urlParams.testId ).split( "," );
- for (var i = 0; i < urlParams.testId.length; i++ ) {
- config.testId.push( urlParams.testId[ i ] );
- }
-}
-
-var loggingCallbacks = {};
-
-// Register logging callbacks
-function registerLoggingCallbacks( obj ) {
- var i, l, key,
- callbackNames = [ "begin", "done", "log", "testStart", "testDone",
- "moduleStart", "moduleDone" ];
-
- function registerLoggingCallback( key ) {
- var loggingCallback = function( callback ) {
- if ( objectType( callback ) !== "function" ) {
- throw new Error(
- "QUnit logging methods require a callback function as their first parameters."
- );
- }
-
- config.callbacks[ key ].push( callback );
- };
-
- // DEPRECATED: This will be removed on QUnit 2.0.0+
- // Stores the registered functions allowing restoring
- // at verifyLoggingCallbacks() if modified
- loggingCallbacks[ key ] = loggingCallback;
-
- return loggingCallback;
- }
-
- for ( i = 0, l = callbackNames.length; i < l; i++ ) {
- key = callbackNames[ i ];
-
- // Initialize key collection of logging callback
- if ( objectType( config.callbacks[ key ] ) === "undefined" ) {
- config.callbacks[ key ] = [];
- }
-
- obj[ key ] = registerLoggingCallback( key );
- }
-}
-
-function runLoggingCallbacks( key, args ) {
- var i, l, callbacks;
-
- callbacks = config.callbacks[ key ];
- for ( i = 0, l = callbacks.length; i < l; i++ ) {
- callbacks[ i ]( args );
- }
-}
-
-// DEPRECATED: This will be removed on 2.0.0+
-// This function verifies if the loggingCallbacks were modified by the user
-// If so, it will restore it, assign the given callback and print a console warning
-function verifyLoggingCallbacks() {
- var loggingCallback, userCallback;
-
- for ( loggingCallback in loggingCallbacks ) {
- if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) {
-
- userCallback = QUnit[ loggingCallback ];
-
- // Restore the callback function
- QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ];
-
- // Assign the deprecated given callback
- QUnit[ loggingCallback ]( userCallback );
-
- if ( global.console && global.console.warn ) {
- global.console.warn(
- "QUnit." + loggingCallback + " was replaced with a new value.\n" +
- "Please, check out the documentation on how to apply logging callbacks.\n" +
- "Reference: https://api.qunitjs.com/category/callbacks/"
- );
- }
- }
- }
-}
-
-( function() {
- if ( !defined.document ) {
- return;
- }
-
- // `onErrorFnPrev` initialized at top of scope
- // Preserve other handlers
- var onErrorFnPrev = window.onerror;
-
- // Cover uncaught exceptions
- // Returning true will suppress the default browser handler,
- // returning false will let it run.
- window.onerror = function( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not suppressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend(function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: true } ) );
- }
- return false;
- }
-
- return ret;
- };
-} )();
-
-QUnit.urlParams = urlParams;
-
-// Figure out if we're running the tests from a server or not
-QUnit.isLocal = !( defined.document && window.location.protocol !== "file:" );
-
-// Expose the current QUnit version
-QUnit.version = "1.21.0";
-
-extend( QUnit, {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment, executeNow ) {
- var module, moduleFns;
- var currentModule = config.currentModule;
-
- if ( arguments.length === 2 ) {
- if ( testEnvironment instanceof Function ) {
- executeNow = testEnvironment;
- testEnvironment = undefined;
- }
- }
-
- // DEPRECATED: handles setup/teardown functions,
- // beforeEach and afterEach should be used instead
- if ( testEnvironment && testEnvironment.setup ) {
- testEnvironment.beforeEach = testEnvironment.setup;
- delete testEnvironment.setup;
- }
- if ( testEnvironment && testEnvironment.teardown ) {
- testEnvironment.afterEach = testEnvironment.teardown;
- delete testEnvironment.teardown;
- }
-
- module = createModule();
-
- moduleFns = {
- beforeEach: setHook( module, "beforeEach" ),
- afterEach: setHook( module, "afterEach" )
- };
-
- if ( executeNow instanceof Function ) {
- config.moduleStack.push( module );
- setCurrentModule( module );
- executeNow.call( module.testEnvironment, moduleFns );
- config.moduleStack.pop();
- module = module.parentModule || currentModule;
- }
-
- setCurrentModule( module );
-
- function createModule() {
- var parentModule = config.moduleStack.length ?
- config.moduleStack.slice( -1 )[ 0 ] : null;
- var moduleName = parentModule !== null ?
- [ parentModule.name, name ].join( " > " ) : name;
- var module = {
- name: moduleName,
- parentModule: parentModule,
- tests: []
- };
-
- var env = {};
- if ( parentModule ) {
- extend( env, parentModule.testEnvironment );
- delete env.beforeEach;
- delete env.afterEach;
- }
- extend( env, testEnvironment );
- module.testEnvironment = env;
-
- config.modules.push( module );
- return module;
- }
-
- function setCurrentModule( module ) {
- config.currentModule = module;
- }
-
- },
-
- // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0.
- asyncTest: asyncTest,
-
- test: test,
-
- skip: skip,
-
- only: only,
-
- // DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0.
- // In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior.
- start: function( count ) {
- var globalStartAlreadyCalled = globalStartCalled;
-
- if ( !config.current ) {
- globalStartCalled = true;
-
- if ( runStarted ) {
- throw new Error( "Called start() outside of a test context while already started" );
- } else if ( globalStartAlreadyCalled || count > 1 ) {
- throw new Error( "Called start() outside of a test context too many times" );
- } else if ( config.autostart ) {
- throw new Error( "Called start() outside of a test context when " +
- "QUnit.config.autostart was true" );
- } else if ( !config.pageLoaded ) {
-
- // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it
- config.autostart = true;
- return;
- }
- } else {
-
- // If a test is running, adjust its semaphore
- config.current.semaphore -= count || 1;
-
- // If semaphore is non-numeric, throw error
- if ( isNaN( config.current.semaphore ) ) {
- config.current.semaphore = 0;
-
- QUnit.pushFailure(
- "Called start() with a non-numeric decrement.",
- sourceFromStacktrace( 2 )
- );
- return;
- }
-
- // Don't start until equal number of stop-calls
- if ( config.current.semaphore > 0 ) {
- return;
- }
-
- // throw an Error if start is called more often than stop
- if ( config.current.semaphore < 0 ) {
- config.current.semaphore = 0;
-
- QUnit.pushFailure(
- "Called start() while already started (test's semaphore was 0 already)",
- sourceFromStacktrace( 2 )
- );
- return;
- }
- }
-
- resumeProcessing();
- },
-
- // DEPRECATED: QUnit.stop() will be removed in QUnit 2.0.
- stop: function( count ) {
-
- // If there isn't a test running, don't allow QUnit.stop() to be called
- if ( !config.current ) {
- throw new Error( "Called stop() outside of a test context" );
- }
-
- // If a test is running, adjust its semaphore
- config.current.semaphore += count || 1;
-
- pauseProcessing();
- },
-
- config: config,
-
- is: is,
-
- objectType: objectType,
-
- extend: extend,
-
- load: function() {
- config.pageLoaded = true;
-
- // Initialize the configuration options
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: 0,
- updateRate: 1000,
- autostart: true,
- filter: ""
- }, true );
-
- config.blocking = false;
-
- if ( config.autostart ) {
- resumeProcessing();
- }
- },
-
- stack: function( offset ) {
- offset = ( offset || 0 ) + 2;
- return sourceFromStacktrace( offset );
- }
-});
-
-registerLoggingCallbacks( QUnit );
-
-function begin() {
- var i, l,
- modulesLog = [];
-
- // If the test run hasn't officially begun yet
- if ( !config.started ) {
-
- // Record the time of the test run's beginning
- config.started = now();
-
- verifyLoggingCallbacks();
-
- // Delete the loose unnamed module if unused.
- if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) {
- config.modules.shift();
- }
-
- // Avoid unnecessary information by not logging modules' test environments
- for ( i = 0, l = config.modules.length; i < l; i++ ) {
- modulesLog.push({
- name: config.modules[ i ].name,
- tests: config.modules[ i ].tests
- });
- }
-
- // The test run is officially beginning now
- runLoggingCallbacks( "begin", {
- totalTests: Test.count,
- modules: modulesLog
- });
- }
-
- config.blocking = false;
- process( true );
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = now();
- config.depth = ( config.depth || 0 ) + 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 ||
- ( ( now() - start ) < config.updateRate ) ) {
- if ( config.current ) {
-
- // Reset async tracking for each phase of the Test lifecycle
- config.current.usedAsync = false;
- }
- config.queue.shift()();
- } else {
- setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function pauseProcessing() {
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = setTimeout(function() {
- if ( config.current ) {
- config.current.semaphore = 0;
- QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) );
- } else {
- throw new Error( "Test timed out" );
- }
- resumeProcessing();
- }, config.testTimeout );
- }
-}
-
-function resumeProcessing() {
- runStarted = true;
-
- // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.)
- if ( defined.setTimeout ) {
- setTimeout(function() {
- if ( config.current && config.current.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- begin();
- }, 13 );
- } else {
- begin();
- }
-}
-
-function done() {
- var runtime, passed;
-
- config.autorun = true;
-
- // Log the last module results
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", {
- name: config.previousModule.name,
- tests: config.previousModule.tests,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all,
- runtime: now() - config.moduleStats.started
- });
- }
- delete config.previousModule;
-
- runtime = now() - config.started;
- passed = config.stats.all - config.stats.bad;
-
- runLoggingCallbacks( "done", {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-function setHook( module, hookName ) {
- if ( module.testEnvironment === undefined ) {
- module.testEnvironment = {};
- }
-
- return function( callback ) {
- module.testEnvironment[ hookName ] = callback;
- };
-}
-
-var focused = false;
-var priorityCount = 0;
-
-function Test( settings ) {
- var i, l;
-
- ++Test.count;
-
- extend( this, settings );
- this.assertions = [];
- this.semaphore = 0;
- this.usedAsync = false;
- this.module = config.currentModule;
- this.stack = sourceFromStacktrace( 3 );
-
- // Register unique strings
- for ( i = 0, l = this.module.tests; i < l.length; i++ ) {
- if ( this.module.tests[ i ].name === this.testName ) {
- this.testName += " ";
- }
- }
-
- this.testId = generateHash( this.module.name, this.testName );
-
- this.module.tests.push({
- name: this.testName,
- testId: this.testId
- });
-
- if ( settings.skip ) {
-
- // Skipped tests will fully ignore any sent callback
- this.callback = function() {};
- this.async = false;
- this.expected = 0;
- } else {
- this.assert = new Assert( this );
- }
-}
-
-Test.count = 0;
-
-Test.prototype = {
- before: function() {
- if (
-
- // Emit moduleStart when we're switching from one module to another
- this.module !== config.previousModule ||
-
- // They could be equal (both undefined) but if the previousModule property doesn't
- // yet exist it means this is the first test in a suite that isn't wrapped in a
- // module, in which case we'll just emit a moduleStart event for 'undefined'.
- // Without this, reporters can get testStart before moduleStart which is a problem.
- !hasOwn.call( config, "previousModule" )
- ) {
- if ( hasOwn.call( config, "previousModule" ) ) {
- runLoggingCallbacks( "moduleDone", {
- name: config.previousModule.name,
- tests: config.previousModule.tests,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all,
- runtime: now() - config.moduleStats.started
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0, started: now() };
- runLoggingCallbacks( "moduleStart", {
- name: this.module.name,
- tests: this.module.tests
- });
- }
-
- config.current = this;
-
- if ( this.module.testEnvironment ) {
- delete this.module.testEnvironment.beforeEach;
- delete this.module.testEnvironment.afterEach;
- }
- this.testEnvironment = extend( {}, this.module.testEnvironment );
-
- this.started = now();
- runLoggingCallbacks( "testStart", {
- name: this.testName,
- module: this.module.name,
- testId: this.testId
- });
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- },
-
- run: function() {
- var promise;
-
- config.current = this;
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = now();
-
- if ( config.notrycatch ) {
- runTest( this );
- return;
- }
-
- try {
- runTest( this );
- } catch ( e ) {
- this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " +
- this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
-
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
-
- function runTest( test ) {
- promise = test.callback.call( test.testEnvironment, test.assert );
- test.resolvePromise( promise );
- }
- },
-
- after: function() {
- checkPollution();
- },
-
- queueHook: function( hook, hookName ) {
- var promise,
- test = this;
- return function runHook() {
- config.current = test;
- if ( config.notrycatch ) {
- callHook();
- return;
- }
- try {
- callHook();
- } catch ( error ) {
- test.pushFailure( hookName + " failed on " + test.testName + ": " +
- ( error.message || error ), extractStacktrace( error, 0 ) );
- }
-
- function callHook() {
- promise = hook.call( test.testEnvironment, test.assert );
- test.resolvePromise( promise, hookName );
- }
- };
- },
-
- // Currently only used for module level hooks, can be used to add global level ones
- hooks: function( handler ) {
- var hooks = [];
-
- function processHooks( test, module ) {
- if ( module.parentModule ) {
- processHooks( test, module.parentModule );
- }
- if ( module.testEnvironment &&
- QUnit.objectType( module.testEnvironment[ handler ] ) === "function" ) {
- hooks.push( test.queueHook( module.testEnvironment[ handler ], handler ) );
- }
- }
-
- // Hooks are ignored on skipped tests
- if ( !this.skip ) {
- processHooks( this, this.module );
- }
- return hooks;
- },
-
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- this.pushFailure( "Expected number of assertions to be defined, but expect() was " +
- "not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- this.pushFailure( "Expected " + this.expected + " assertions, but " +
- this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- this.pushFailure( "Expected at least one assertion, but none were run - call " +
- "expect(0) to accept zero assertions.", this.stack );
- }
-
- var i,
- bad = 0;
-
- this.runtime = now() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[ i ].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- runLoggingCallbacks( "testDone", {
- name: this.testName,
- module: this.module.name,
- skipped: !!this.skip,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- runtime: this.runtime,
-
- // HTML Reporter use
- assertions: this.assertions,
- testId: this.testId,
-
- // Source of Test
- source: this.stack,
-
- // DEPRECATED: this property will be removed in 2.0.0, use runtime instead
- duration: this.runtime
- });
-
- // QUnit.reset() is deprecated and will be replaced for a new
- // fixture reset function on QUnit 2.0/2.1.
- // It's still called here for backwards compatibility handling
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var priority,
- test = this;
-
- if ( !this.valid() ) {
- return;
- }
-
- function run() {
-
- // each of these can by async
- synchronize([
- function() {
- test.before();
- },
-
- test.hooks( "beforeEach" ),
- function() {
- test.run();
- },
-
- test.hooks( "afterEach" ).reverse(),
-
- function() {
- test.after();
- },
- function() {
- test.finish();
- }
- ]);
- }
-
- // Prioritize previously failed tests, detected from sessionStorage
- priority = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName );
-
- return synchronize( run, priority );
- },
-
- push: function( result, actual, expected, message, negative ) {
- var source,
- details = {
- module: this.module.name,
- name: this.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected,
- testId: this.testId,
- negative: negative || false,
- runtime: now() - this.started
- };
-
- if ( !result ) {
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- }
- }
-
- runLoggingCallbacks( "log", details );
-
- this.assertions.push({
- result: !!result,
- message: message
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !( this instanceof Test ) ) {
- throw new Error( "pushFailure() assertion outside test context, was " +
- sourceFromStacktrace( 2 ) );
- }
-
- var details = {
- module: this.module.name,
- name: this.testName,
- result: false,
- message: message || "error",
- actual: actual || null,
- testId: this.testId,
- runtime: now() - this.started
- };
-
- if ( source ) {
- details.source = source;
- }
-
- runLoggingCallbacks( "log", details );
-
- this.assertions.push({
- result: false,
- message: message
- });
- },
-
- resolvePromise: function( promise, phase ) {
- var then, message,
- test = this;
- if ( promise != null ) {
- then = promise.then;
- if ( QUnit.objectType( then ) === "function" ) {
- QUnit.stop();
- then.call(
- promise,
- function() { QUnit.start(); },
- function( error ) {
- message = "Promise rejected " +
- ( !phase ? "during" : phase.replace( /Each$/, "" ) ) +
- " " + test.testName + ": " + ( error.message || error );
- test.pushFailure( message, extractStacktrace( error, 0 ) );
-
- // else next test will carry the responsibility
- saveGlobal();
-
- // Unblock
- QUnit.start();
- }
- );
- }
- }
- },
-
- valid: function() {
- var filter = config.filter,
- regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec( filter ),
- module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(),
- fullName = ( this.module.name + ": " + this.testName );
-
- function testInModuleChain( testModule ) {
- var testModuleName = testModule.name ? testModule.name.toLowerCase() : null;
- if ( testModuleName === module ) {
- return true;
- } else if ( testModule.parentModule ) {
- return testInModuleChain( testModule.parentModule );
- } else {
- return false;
- }
- }
-
- // Internally-generated tests are always valid
- if ( this.callback && this.callback.validTest ) {
- return true;
- }
-
- if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) {
- return false;
- }
-
- if ( module && !testInModuleChain( this.module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- return regexFilter ?
- this.regexFilter( !!regexFilter[1], regexFilter[2], regexFilter[3], fullName ) :
- this.stringFilter( filter, fullName );
- },
-
- regexFilter: function( exclude, pattern, flags, fullName ) {
- var regex = new RegExp( pattern, flags );
- var match = regex.test( fullName );
-
- return match !== exclude;
- },
-
- stringFilter: function( filter, fullName ) {
- filter = filter.toLowerCase();
- fullName = fullName.toLowerCase();
-
- var include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
- }
-};
-
-// Resets the test setup. Useful for tests that modify the DOM.
-/*
-DEPRECATED: Use multiple tests instead of resetting inside a test.
-Use testStart or testDone for custom cleanup.
-This method will throw an error in 2.0, and will be removed in 2.1
-*/
-QUnit.reset = function() {
-
- // Return on non-browser environments
- // This is necessary to not break on node tests
- if ( !defined.document ) {
- return;
- }
-
- var fixture = defined.document && document.getElementById &&
- document.getElementById( "qunit-fixture" );
-
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
-};
-
-QUnit.pushFailure = function() {
- if ( !QUnit.config.current ) {
- throw new Error( "pushFailure() assertion outside test context, in " +
- sourceFromStacktrace( 2 ) );
- }
-
- // Gets current test obj
- var currentTest = QUnit.config.current;
-
- return currentTest.pushFailure.apply( currentTest, arguments );
-};
-
-// Based on Java's String.hashCode, a simple but not
-// rigorously collision resistant hashing function
-function generateHash( module, testName ) {
- var hex,
- i = 0,
- hash = 0,
- str = module + "\x1C" + testName,
- len = str.length;
-
- for ( ; i < len; i++ ) {
- hash = ( ( hash << 5 ) - hash ) + str.charCodeAt( i );
- hash |= 0;
- }
-
- // Convert the possibly negative integer hash code into an 8 character hex string, which isn't
- // strictly necessary but increases user understanding that the id is a SHA-like hash
- hex = ( 0x100000000 + hash ).toString( 16 );
- if ( hex.length < 8 ) {
- hex = "0000000" + hex;
- }
-
- return hex.slice( -8 );
-}
-
-function synchronize( callback, priority ) {
- var last = !priority;
-
- if ( QUnit.objectType( callback ) === "array" ) {
- while ( callback.length ) {
- synchronize( callback.shift() );
- }
- return;
- }
-
- if ( priority ) {
- config.queue.splice( priorityCount++, 0, callback );
- } else {
- config.queue.push( callback );
- }
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in global ) {
- if ( hasOwn.call( global, key ) ) {
-
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) );
- }
-}
-
-// Will be exposed as QUnit.asyncTest
-function asyncTest( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
-}
-
-// Will be exposed as QUnit.test
-function test( testName, expected, callback, async ) {
- if ( focused ) { return; }
-
- var newTest;
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- newTest = new Test({
- testName: testName,
- expected: expected,
- async: async,
- callback: callback
- });
-
- newTest.queue();
-}
-
-// Will be exposed as QUnit.skip
-function skip( testName ) {
- if ( focused ) { return; }
-
- var test = new Test({
- testName: testName,
- skip: true
- });
-
- test.queue();
-}
-
-// Will be exposed as QUnit.only
-function only( testName, expected, callback, async ) {
- var newTest;
-
- if ( focused ) { return; }
-
- QUnit.config.queue.length = 0;
- focused = true;
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- newTest = new Test({
- testName: testName,
- expected: expected,
- async: async,
- callback: callback
- });
-
- newTest.queue();
-}
-
-function Assert( testContext ) {
- this.test = testContext;
-}
-
-// Assert helpers
-QUnit.assert = Assert.prototype = {
-
- // Specify the number of expected assertions to guarantee that failed test
- // (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if ( arguments.length === 1 ) {
- this.test.expected = asserts;
- } else {
- return this.test.expected;
- }
- },
-
- // Increment this Test's semaphore counter, then return a function that
- // decrements that counter a maximum of once.
- async: function( count ) {
- var test = this.test,
- popped = false,
- acceptCallCount = count;
-
- if ( typeof acceptCallCount === "undefined" ) {
- acceptCallCount = 1;
- }
-
- test.semaphore += 1;
- test.usedAsync = true;
- pauseProcessing();
-
- return function done() {
-
- if ( popped ) {
- test.pushFailure( "Too many calls to the `assert.async` callback",
- sourceFromStacktrace( 2 ) );
- return;
- }
- acceptCallCount -= 1;
- if ( acceptCallCount > 0 ) {
- return;
- }
-
- test.semaphore -= 1;
- popped = true;
- resumeProcessing();
- };
- },
-
- // Exports test.push() to the user API
- push: function( /* result, actual, expected, message, negative */ ) {
- var assert = this,
- currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current;
-
- // Backwards compatibility fix.
- // Allows the direct use of global exported assertions and QUnit.assert.*
- // Although, it's use is not recommended as it can leak assertions
- // to other tests from async tests, because we only get a reference to the current test,
- // not exactly the test where assertion were intended to be called.
- if ( !currentTest ) {
- throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) );
- }
-
- if ( currentTest.usedAsync === true && currentTest.semaphore === 0 ) {
- currentTest.pushFailure( "Assertion after the final `assert.async` was resolved",
- sourceFromStacktrace( 2 ) );
-
- // Allow this assertion to continue running anyway...
- }
-
- if ( !( assert instanceof Assert ) ) {
- assert = currentTest.assert;
- }
- return assert.test.push.apply( assert.test, arguments );
- },
-
- ok: function( result, message ) {
- message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " +
- QUnit.dump.parse( result ) );
- this.push( !!result, result, true, message );
- },
-
- notOk: function( result, message ) {
- message = message || ( !result ? "okay" : "failed, expected argument to be falsy, was: " +
- QUnit.dump.parse( result ) );
- this.push( !result, result, false, message );
- },
-
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- this.push( expected == actual, actual, expected, message );
- },
-
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- this.push( expected != actual, actual, expected, message, true );
- },
-
- propEqual: function( actual, expected, message ) {
- actual = objectValues( actual );
- expected = objectValues( expected );
- this.push( QUnit.equiv( actual, expected ), actual, expected, message );
- },
-
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues( actual );
- expected = objectValues( expected );
- this.push( !QUnit.equiv( actual, expected ), actual, expected, message, true );
- },
-
- deepEqual: function( actual, expected, message ) {
- this.push( QUnit.equiv( actual, expected ), actual, expected, message );
- },
-
- notDeepEqual: function( actual, expected, message ) {
- this.push( !QUnit.equiv( actual, expected ), actual, expected, message, true );
- },
-
- strictEqual: function( actual, expected, message ) {
- this.push( expected === actual, actual, expected, message );
- },
-
- notStrictEqual: function( actual, expected, message ) {
- this.push( expected !== actual, actual, expected, message, true );
- },
-
- "throws": function( block, expected, message ) {
- var actual, expectedType,
- expectedOutput = expected,
- ok = false,
- currentTest = ( this instanceof Assert && this.test ) || QUnit.config.current;
-
- // 'expected' is optional unless doing string comparison
- if ( message == null && typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- currentTest.ignoreGlobalErrors = true;
- try {
- block.call( currentTest.testEnvironment );
- } catch (e) {
- actual = e;
- }
- currentTest.ignoreGlobalErrors = false;
-
- if ( actual ) {
- expectedType = QUnit.objectType( expected );
-
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
-
- // expected is a regexp
- } else if ( expectedType === "regexp" ) {
- ok = expected.test( errorString( actual ) );
-
- // expected is a string
- } else if ( expectedType === "string" ) {
- ok = expected === errorString( actual );
-
- // expected is a constructor, maybe an Error constructor
- } else if ( expectedType === "function" && actual instanceof expected ) {
- ok = true;
-
- // expected is an Error object
- } else if ( expectedType === "object" ) {
- ok = actual instanceof expected.constructor &&
- actual.name === expected.name &&
- actual.message === expected.message;
-
- // expected is a validation function which returns true if validation passed
- } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
- }
-
- currentTest.assert.push( ok, actual, expectedOutput, message );
- }
-};
-
-// Provide an alternative to assert.throws(), for environments that consider throws a reserved word
-// Known to us are: Closure Compiler, Narwhal
-(function() {
- /*jshint sub:true */
- Assert.prototype.raises = Assert.prototype[ "throws" ];
-}());
-
-function errorString( error ) {
- var name, message,
- resultErrorString = error.toString();
- if ( resultErrorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return resultErrorString;
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé <prathe@gmail.com>
-QUnit.equiv = (function() {
-
- // Stack to decide between skip/abort functions
- var callers = [];
-
- // Stack to avoiding loops from circular referencing
- var parents = [];
- var parentsB = [];
-
- var getProto = Object.getPrototypeOf || function( obj ) {
-
- /*jshint proto: true */
- return obj.__proto__;
- };
-
- function useStrictEquality( b, a ) {
-
- // To catch short annotation VS 'new' annotation of a declaration. e.g.:
- // `var i = 1;`
- // `var j = new Number(1);`
- if ( typeof a === "object" ) {
- a = a.valueOf();
- }
- if ( typeof b === "object" ) {
- b = b.valueOf();
- }
-
- return a === b;
- }
-
- function compareConstructors( a, b ) {
- var protoA = getProto( a );
- var protoB = getProto( b );
-
- // Comparing constructors is more strict than using `instanceof`
- if ( a.constructor === b.constructor ) {
- return true;
- }
-
- // Ref #851
- // If the obj prototype descends from a null constructor, treat it
- // as a null prototype.
- if ( protoA && protoA.constructor === null ) {
- protoA = null;
- }
- if ( protoB && protoB.constructor === null ) {
- protoB = null;
- }
-
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( ( protoA === null && protoB === Object.prototype ) ||
- ( protoB === null && protoA === Object.prototype ) ) {
- return true;
- }
-
- return false;
- }
-
- function getRegExpFlags( regexp ) {
- return "flags" in regexp ? regexp.flags : regexp.toString().match( /[gimuy]*$/ )[ 0 ];
- }
-
- var callbacks = {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
- "symbol": useStrictEquality,
- "date": useStrictEquality,
-
- "nan": function() {
- return true;
- },
-
- "regexp": function( b, a ) {
- return a.source === b.source &&
-
- // Include flags in the comparison
- getRegExpFlags( a ) === getRegExpFlags( b );
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[ callers.length - 1 ];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop, aCircular, bCircular;
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // Track reference to avoid circular references
- parents.push( a );
- parentsB.push( b );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- aCircular = parents[ j ] === a[ i ];
- bCircular = parentsB[ j ] === b[ i ];
- if ( aCircular || bCircular ) {
- if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
- loop = true;
- } else {
- parents.pop();
- parentsB.pop();
- return false;
- }
- }
- }
- if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
- parents.pop();
- parentsB.pop();
- return false;
- }
- }
- parents.pop();
- parentsB.pop();
- return true;
- },
-
- "set": function( b, a ) {
- var aArray, bArray;
-
- aArray = [];
- a.forEach( function( v ) {
- aArray.push( v );
- });
- bArray = [];
- b.forEach( function( v ) {
- bArray.push( v );
- });
-
- return innerEquiv( bArray, aArray );
- },
-
- "map": function( b, a ) {
- var aArray, bArray;
-
- aArray = [];
- a.forEach( function( v, k ) {
- aArray.push( [ k, v ] );
- });
- bArray = [];
- b.forEach( function( v, k ) {
- bArray.push( [ k, v ] );
- });
-
- return innerEquiv( bArray, aArray );
- },
-
- "object": function( b, a ) {
- var i, j, loop, aCircular, bCircular;
-
- // Default to true
- var eq = true;
- var aProperties = [];
- var bProperties = [];
-
- if ( compareConstructors( a, b ) === false ) {
- return false;
- }
-
- // Stack constructor before traversing properties
- callers.push( a.constructor );
-
- // Track reference to avoid circular references
- parents.push( a );
- parentsB.push( b );
-
- // Be strict: don't ensure hasOwnProperty and go deep
- for ( i in a ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- aCircular = parents[ j ] === a[ i ];
- bCircular = parentsB[ j ] === b[ i ];
- if ( aCircular || bCircular ) {
- if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
- loop = true;
- } else {
- eq = false;
- break;
- }
- }
- }
- aProperties.push( i );
- if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
- eq = false;
- break;
- }
- }
-
- parents.pop();
- parentsB.pop();
-
- // Unstack, we are done
- callers.pop();
-
- for ( i in b ) {
-
- // Collect b's properties
- bProperties.push( i );
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
-
- function typeEquiv( a, b ) {
- var type = QUnit.objectType( a );
- return QUnit.objectType( b ) === type && callbacks[ type ]( b, a );
- }
-
- // The real equiv function
- function innerEquiv( a, b ) {
-
- // We're done when there's nothing more to compare
- if ( arguments.length < 2 ) {
- return true;
- }
-
- // Require type-specific equality
- return ( a === b || typeEquiv( a, b ) ) &&
-
- // ...across all consecutive argument pairs
- ( arguments.length === 2 || innerEquiv.apply( this, [].slice.call( arguments, 1 ) ) );
- }
-
- return innerEquiv;
-}());
-
-// Based on jsDump by Ariel Flesler
-// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
-QUnit.dump = (function() {
- function quote( str ) {
- return "\"" + str.toString().replace( /\\/g, "\\\\" ).replace( /"/g, "\\\"" ) + "\"";
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = dump.separator(),
- base = dump.indent(),
- inner = dump.indent( 1 );
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join( s );
- }
- function array( arr, stack ) {
- var i = arr.length,
- ret = new Array( i );
-
- if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
- return "[object Array]";
- }
-
- this.up();
- while ( i-- ) {
- ret[ i ] = this.parse( arr[ i ], undefined, stack );
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- dump = {
-
- // objType is used mostly internally, you can fix a (custom) type in advance
- parse: function( obj, objType, stack ) {
- stack = stack || [];
- var res, parser, parserType,
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + ( inStack - stack.length ) + ")";
- }
-
- objType = objType || this.typeOf( obj );
- parser = this.parsers[ objType ];
- parserType = typeof parser;
-
- if ( parserType === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( parserType === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj ) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj ) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj ) ) {
- type = "function";
- } else if ( obj.setInterval !== undefined &&
- obj.document !== undefined &&
- obj.nodeType === undefined ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
-
- // native arrays
- toString.call( obj ) === "[object Array]" ||
-
- // NodeList objects
- ( typeof obj.length === "number" && obj.item !== undefined &&
- ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null &&
- obj[ 0 ] === undefined ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this.depth + ( extra || 0 ) ).join( chr );
- },
- up: function( a ) {
- this.depth += a || 1;
- },
- down: function( a ) {
- this.depth -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[ name ] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- depth: 1,
- maxDepth: QUnit.config.maxDepth,
-
- // This is the list of parsers, to modify them, use dump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function( error ) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
-
- // functions never have name in IE
- name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, dump.parse( fn, "functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var keys, key, val, i, nonEnumerableProperties,
- ret = [];
-
- if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
- return "[object Object]";
- }
-
- dump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
-
- // Some properties are not always enumerable on Error objects.
- nonEnumerableProperties = [ "message", "name" ];
- for ( i in nonEnumerableProperties ) {
- key = nonEnumerableProperties[ i ];
- if ( key in map && inArray( key, keys ) < 0 ) {
- keys.push( key );
- }
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( dump.parse( key, "key" ) + ": " +
- dump.parse( val, undefined, stack ) );
- }
- dump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = dump.HTML ? "<" : "<",
- close = dump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[ i ].nodeValue;
-
- // IE6 includes all attributes in .attributes, even ones not explicitly
- // set. Those have values like undefined, null, 0, false, "" or
- // "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[ i ].nodeName + "=" +
- dump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
-
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array( l );
- while ( l-- ) {
-
- // 97 is 'a'
- args[ l ] = String.fromCharCode( 97 + l );
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's a html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return dump;
-}());
-
-// back compat
-QUnit.jsDump = QUnit.dump;
-
-// For browser, export only select globals
-if ( defined.document ) {
-
- // Deprecated
- // Extend assert methods to QUnit and Global scope through Backwards compatibility
- (function() {
- var i,
- assertions = Assert.prototype;
-
- function applyCurrent( current ) {
- return function() {
- var assert = new Assert( QUnit.config.current );
- current.apply( assert, arguments );
- };
- }
-
- for ( i in assertions ) {
- QUnit[ i ] = applyCurrent( assertions[ i ] );
- }
- })();
-
- (function() {
- var i, l,
- keys = [
- "test",
- "module",
- "expect",
- "asyncTest",
- "start",
- "stop",
- "ok",
- "notOk",
- "equal",
- "notEqual",
- "propEqual",
- "notPropEqual",
- "deepEqual",
- "notDeepEqual",
- "strictEqual",
- "notStrictEqual",
- "throws",
- "raises"
- ];
-
- for ( i = 0, l = keys.length; i < l; i++ ) {
- window[ keys[ i ] ] = QUnit[ keys[ i ] ];
- }
- })();
-
- window.QUnit = QUnit;
-}
-
-// For nodejs
-if ( typeof module !== "undefined" && module && module.exports ) {
- module.exports = QUnit;
-
- // For consistency with CommonJS environments' exports
- module.exports.QUnit = QUnit;
-}
-
-// For CommonJS with exports, but without module.exports, like Rhino
-if ( typeof exports !== "undefined" && exports ) {
- exports.QUnit = QUnit;
-}
-
-if ( typeof define === "function" && define.amd ) {
- define( function() {
- return QUnit;
- } );
- QUnit.config.autostart = false;
-}
-
-/*
- * This file is a modified version of google-diff-match-patch's JavaScript implementation
- * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js),
- * modifications are licensed as more fully set forth in LICENSE.txt.
- *
- * The original source of google-diff-match-patch is attributable and licensed as follows:
- *
- * Copyright 2006 Google Inc.
- * https://code.google.com/p/google-diff-match-patch/
- *
- * 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
- *
- * https://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.
- *
- * More Info:
- * https://code.google.com/p/google-diff-match-patch/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- */
-QUnit.diff = ( function() {
- function DiffMatchPatch() {
- }
-
- // DIFF FUNCTIONS
-
- /**
- * The data structure representing a diff is an array of tuples:
- * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
- * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
- */
- var DIFF_DELETE = -1,
- DIFF_INSERT = 1,
- DIFF_EQUAL = 0;
-
- /**
- * Find the differences between two texts. Simplifies the problem by stripping
- * any common prefix or suffix off the texts before diffing.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @param {boolean=} optChecklines Optional speedup flag. If present and false,
- * then don't run a line-level diff first to identify the changed areas.
- * Defaults to true, which does a faster, slightly less optimal diff.
- * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
- */
- DiffMatchPatch.prototype.DiffMain = function( text1, text2, optChecklines ) {
- var deadline, checklines, commonlength,
- commonprefix, commonsuffix, diffs;
-
- // The diff must be complete in up to 1 second.
- deadline = ( new Date() ).getTime() + 1000;
-
- // Check for null inputs.
- if ( text1 === null || text2 === null ) {
- throw new Error( "Null input. (DiffMain)" );
- }
-
- // Check for equality (speedup).
- if ( text1 === text2 ) {
- if ( text1 ) {
- return [
- [ DIFF_EQUAL, text1 ]
- ];
- }
- return [];
- }
-
- if ( typeof optChecklines === "undefined" ) {
- optChecklines = true;
- }
-
- checklines = optChecklines;
-
- // Trim off common prefix (speedup).
- commonlength = this.diffCommonPrefix( text1, text2 );
- commonprefix = text1.substring( 0, commonlength );
- text1 = text1.substring( commonlength );
- text2 = text2.substring( commonlength );
-
- // Trim off common suffix (speedup).
- commonlength = this.diffCommonSuffix( text1, text2 );
- commonsuffix = text1.substring( text1.length - commonlength );
- text1 = text1.substring( 0, text1.length - commonlength );
- text2 = text2.substring( 0, text2.length - commonlength );
-
- // Compute the diff on the middle block.
- diffs = this.diffCompute( text1, text2, checklines, deadline );
-
- // Restore the prefix and suffix.
- if ( commonprefix ) {
- diffs.unshift( [ DIFF_EQUAL, commonprefix ] );
- }
- if ( commonsuffix ) {
- diffs.push( [ DIFF_EQUAL, commonsuffix ] );
- }
- this.diffCleanupMerge( diffs );
- return diffs;
- };
-
- /**
- * Reduce the number of edits by eliminating operationally trivial equalities.
- * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
- */
- DiffMatchPatch.prototype.diffCleanupEfficiency = function( diffs ) {
- var changes, equalities, equalitiesLength, lastequality,
- pointer, preIns, preDel, postIns, postDel;
- changes = false;
- equalities = []; // Stack of indices where equalities are found.
- equalitiesLength = 0; // Keeping our own length var is faster in JS.
- /** @type {?string} */
- lastequality = null;
- // Always equal to diffs[equalities[equalitiesLength - 1]][1]
- pointer = 0; // Index of current position.
- // Is there an insertion operation before the last equality.
- preIns = false;
- // Is there a deletion operation before the last equality.
- preDel = false;
- // Is there an insertion operation after the last equality.
- postIns = false;
- // Is there a deletion operation after the last equality.
- postDel = false;
- while ( pointer < diffs.length ) {
-
- // Equality found.
- if ( diffs[ pointer ][ 0 ] === DIFF_EQUAL ) {
- if ( diffs[ pointer ][ 1 ].length < 4 && ( postIns || postDel ) ) {
-
- // Candidate found.
- equalities[ equalitiesLength++ ] = pointer;
- preIns = postIns;
- preDel = postDel;
- lastequality = diffs[ pointer ][ 1 ];
- } else {
-
- // Not a candidate, and can never become one.
- equalitiesLength = 0;
- lastequality = null;
- }
- postIns = postDel = false;
-
- // An insertion or deletion.
- } else {
-
- if ( diffs[ pointer ][ 0 ] === DIFF_DELETE ) {
- postDel = true;
- } else {
- postIns = true;
- }
-
- /*
- * Five types to be split:
- * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
- * <ins>A</ins>X<ins>C</ins><del>D</del>
- * <ins>A</ins><del>B</del>X<ins>C</ins>
- * <ins>A</del>X<ins>C</ins><del>D</del>
- * <ins>A</ins><del>B</del>X<del>C</del>
- */
- if ( lastequality && ( ( preIns && preDel && postIns && postDel ) ||
- ( ( lastequality.length < 2 ) &&
- ( preIns + preDel + postIns + postDel ) === 3 ) ) ) {
-
- // Duplicate record.
- diffs.splice(
- equalities[ equalitiesLength - 1 ],
- 0,
- [ DIFF_DELETE, lastequality ]
- );
-
- // Change second copy to insert.
- diffs[ equalities[ equalitiesLength - 1 ] + 1 ][ 0 ] = DIFF_INSERT;
- equalitiesLength--; // Throw away the equality we just deleted;
- lastequality = null;
- if ( preIns && preDel ) {
- // No changes made which could affect previous entry, keep going.
- postIns = postDel = true;
- equalitiesLength = 0;
- } else {
- equalitiesLength--; // Throw away the previous equality.
- pointer = equalitiesLength > 0 ? equalities[ equalitiesLength - 1 ] : -1;
- postIns = postDel = false;
- }
- changes = true;
- }
- }
- pointer++;
- }
-
- if ( changes ) {
- this.diffCleanupMerge( diffs );
- }
- };
-
- /**
- * Convert a diff array into a pretty HTML report.
- * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
- * @param {integer} string to be beautified.
- * @return {string} HTML representation.
- */
- DiffMatchPatch.prototype.diffPrettyHtml = function( diffs ) {
- var op, data, x,
- html = [];
- for ( x = 0; x < diffs.length; x++ ) {
- op = diffs[ x ][ 0 ]; // Operation (insert, delete, equal)
- data = diffs[ x ][ 1 ]; // Text of change.
- switch ( op ) {
- case DIFF_INSERT:
- html[ x ] = "<ins>" + data + "</ins>";
- break;
- case DIFF_DELETE:
- html[ x ] = "<del>" + data + "</del>";
- break;
- case DIFF_EQUAL:
- html[ x ] = "<span>" + data + "</span>";
- break;
- }
- }
- return html.join( "" );
- };
-
- /**
- * Determine the common prefix of two strings.
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {number} The number of characters common to the start of each
- * string.
- */
- DiffMatchPatch.prototype.diffCommonPrefix = function( text1, text2 ) {
- var pointermid, pointermax, pointermin, pointerstart;
- // Quick check for common null cases.
- if ( !text1 || !text2 || text1.charAt( 0 ) !== text2.charAt( 0 ) ) {
- return 0;
- }
- // Binary search.
- // Performance analysis: https://neil.fraser.name/news/2007/10/09/
- pointermin = 0;
- pointermax = Math.min( text1.length, text2.length );
- pointermid = pointermax;
- pointerstart = 0;
- while ( pointermin < pointermid ) {
- if ( text1.substring( pointerstart, pointermid ) ===
- text2.substring( pointerstart, pointermid ) ) {
- pointermin = pointermid;
- pointerstart = pointermin;
- } else {
- pointermax = pointermid;
- }
- pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin );
- }
- return pointermid;
- };
-
- /**
- * Determine the common suffix of two strings.
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {number} The number of characters common to the end of each string.
- */
- DiffMatchPatch.prototype.diffCommonSuffix = function( text1, text2 ) {
- var pointermid, pointermax, pointermin, pointerend;
- // Quick check for common null cases.
- if ( !text1 ||
- !text2 ||
- text1.charAt( text1.length - 1 ) !== text2.charAt( text2.length - 1 ) ) {
- return 0;
- }
- // Binary search.
- // Performance analysis: https://neil.fraser.name/news/2007/10/09/
- pointermin = 0;
- pointermax = Math.min( text1.length, text2.length );
- pointermid = pointermax;
- pointerend = 0;
- while ( pointermin < pointermid ) {
- if ( text1.substring( text1.length - pointermid, text1.length - pointerend ) ===
- text2.substring( text2.length - pointermid, text2.length - pointerend ) ) {
- pointermin = pointermid;
- pointerend = pointermin;
- } else {
- pointermax = pointermid;
- }
- pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin );
- }
- return pointermid;
- };
-
- /**
- * Find the differences between two texts. Assumes that the texts do not
- * have any common prefix or suffix.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @param {boolean} checklines Speedup flag. If false, then don't run a
- * line-level diff first to identify the changed areas.
- * If true, then run a faster, slightly less optimal diff.
- * @param {number} deadline Time when the diff should be complete by.
- * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
- * @private
- */
- DiffMatchPatch.prototype.diffCompute = function( text1, text2, checklines, deadline ) {
- var diffs, longtext, shorttext, i, hm,
- text1A, text2A, text1B, text2B,
- midCommon, diffsA, diffsB;
-
- if ( !text1 ) {
- // Just add some text (speedup).
- return [
- [ DIFF_INSERT, text2 ]
- ];
- }
-
- if ( !text2 ) {
- // Just delete some text (speedup).
- return [
- [ DIFF_DELETE, text1 ]
- ];
- }
-
- longtext = text1.length > text2.length ? text1 : text2;
- shorttext = text1.length > text2.length ? text2 : text1;
- i = longtext.indexOf( shorttext );
- if ( i !== -1 ) {
- // Shorter text is inside the longer text (speedup).
- diffs = [
- [ DIFF_INSERT, longtext.substring( 0, i ) ],
- [ DIFF_EQUAL, shorttext ],
- [ DIFF_INSERT, longtext.substring( i + shorttext.length ) ]
- ];
- // Swap insertions for deletions if diff is reversed.
- if ( text1.length > text2.length ) {
- diffs[ 0 ][ 0 ] = diffs[ 2 ][ 0 ] = DIFF_DELETE;
- }
- return diffs;
- }
-
- if ( shorttext.length === 1 ) {
- // Single character string.
- // After the previous speedup, the character can't be an equality.
- return [
- [ DIFF_DELETE, text1 ],
- [ DIFF_INSERT, text2 ]
- ];
- }
-
- // Check to see if the problem can be split in two.
- hm = this.diffHalfMatch( text1, text2 );
- if ( hm ) {
- // A half-match was found, sort out the return data.
- text1A = hm[ 0 ];
- text1B = hm[ 1 ];
- text2A = hm[ 2 ];
- text2B = hm[ 3 ];
- midCommon = hm[ 4 ];
- // Send both pairs off for separate processing.
- diffsA = this.DiffMain( text1A, text2A, checklines, deadline );
- diffsB = this.DiffMain( text1B, text2B, checklines, deadline );
- // Merge the results.
- return diffsA.concat( [
- [ DIFF_EQUAL, midCommon ]
- ], diffsB );
- }
-
- if ( checklines && text1.length > 100 && text2.length > 100 ) {
- return this.diffLineMode( text1, text2, deadline );
- }
-
- return this.diffBisect( text1, text2, deadline );
- };
-
- /**
- * Do the two texts share a substring which is at least half the length of the
- * longer text?
- * This speedup can produce non-minimal diffs.
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {Array.<string>} Five element Array, containing the prefix of
- * text1, the suffix of text1, the prefix of text2, the suffix of
- * text2 and the common middle. Or null if there was no match.
- * @private
- */
- DiffMatchPatch.prototype.diffHalfMatch = function( text1, text2 ) {
- var longtext, shorttext, dmp,
- text1A, text2B, text2A, text1B, midCommon,
- hm1, hm2, hm;
-
- longtext = text1.length > text2.length ? text1 : text2;
- shorttext = text1.length > text2.length ? text2 : text1;
- if ( longtext.length < 4 || shorttext.length * 2 < longtext.length ) {
- return null; // Pointless.
- }
- dmp = this; // 'this' becomes 'window' in a closure.
-
- /**
- * Does a substring of shorttext exist within longtext such that the substring
- * is at least half the length of longtext?
- * Closure, but does not reference any external variables.
- * @param {string} longtext Longer string.
- * @param {string} shorttext Shorter string.
- * @param {number} i Start index of quarter length substring within longtext.
- * @return {Array.<string>} Five element Array, containing the prefix of
- * longtext, the suffix of longtext, the prefix of shorttext, the suffix
- * of shorttext and the common middle. Or null if there was no match.
- * @private
- */
- function diffHalfMatchI( longtext, shorttext, i ) {
- var seed, j, bestCommon, prefixLength, suffixLength,
- bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB;
- // Start with a 1/4 length substring at position i as a seed.
- seed = longtext.substring( i, i + Math.floor( longtext.length / 4 ) );
- j = -1;
- bestCommon = "";
- while ( ( j = shorttext.indexOf( seed, j + 1 ) ) !== -1 ) {
- prefixLength = dmp.diffCommonPrefix( longtext.substring( i ),
- shorttext.substring( j ) );
- suffixLength = dmp.diffCommonSuffix( longtext.substring( 0, i ),
- shorttext.substring( 0, j ) );
- if ( bestCommon.length < suffixLength + prefixLength ) {
- bestCommon = shorttext.substring( j - suffixLength, j ) +
- shorttext.substring( j, j + prefixLength );
- bestLongtextA = longtext.substring( 0, i - suffixLength );
- bestLongtextB = longtext.substring( i + prefixLength );
- bestShorttextA = shorttext.substring( 0, j - suffixLength );
- bestShorttextB = shorttext.substring( j + prefixLength );
- }
- }
- if ( bestCommon.length * 2 >= longtext.length ) {
- return [ bestLongtextA, bestLongtextB,
- bestShorttextA, bestShorttextB, bestCommon
- ];
- } else {
- return null;
- }
- }
-
- // First check if the second quarter is the seed for a half-match.
- hm1 = diffHalfMatchI( longtext, shorttext,
- Math.ceil( longtext.length / 4 ) );
- // Check again based on the third quarter.
- hm2 = diffHalfMatchI( longtext, shorttext,
- Math.ceil( longtext.length / 2 ) );
- if ( !hm1 && !hm2 ) {
- return null;
- } else if ( !hm2 ) {
- hm = hm1;
- } else if ( !hm1 ) {
- hm = hm2;
- } else {
- // Both matched. Select the longest.
- hm = hm1[ 4 ].length > hm2[ 4 ].length ? hm1 : hm2;
- }
-
- // A half-match was found, sort out the return data.
- text1A, text1B, text2A, text2B;
- if ( text1.length > text2.length ) {
- text1A = hm[ 0 ];
- text1B = hm[ 1 ];
- text2A = hm[ 2 ];
- text2B = hm[ 3 ];
- } else {
- text2A = hm[ 0 ];
- text2B = hm[ 1 ];
- text1A = hm[ 2 ];
- text1B = hm[ 3 ];
- }
- midCommon = hm[ 4 ];
- return [ text1A, text1B, text2A, text2B, midCommon ];
- };
-
- /**
- * Do a quick line-level diff on both strings, then rediff the parts for
- * greater accuracy.
- * This speedup can produce non-minimal diffs.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @param {number} deadline Time when the diff should be complete by.
- * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
- * @private
- */
- DiffMatchPatch.prototype.diffLineMode = function( text1, text2, deadline ) {
- var a, diffs, linearray, pointer, countInsert,
- countDelete, textInsert, textDelete, j;
- // Scan the text on a line-by-line basis first.
- a = this.diffLinesToChars( text1, text2 );
- text1 = a.chars1;
- text2 = a.chars2;
- linearray = a.lineArray;
-
- diffs = this.DiffMain( text1, text2, false, deadline );
-
- // Convert the diff back to original text.
- this.diffCharsToLines( diffs, linearray );
- // Eliminate freak matches (e.g. blank lines)
- this.diffCleanupSemantic( diffs );
-
- // Rediff any replacement blocks, this time character-by-character.
- // Add a dummy entry at the end.
- diffs.push( [ DIFF_EQUAL, "" ] );
- pointer = 0;
- countDelete = 0;
- countInsert = 0;
- textDelete = "";
- textInsert = "";
- while ( pointer < diffs.length ) {
- switch ( diffs[ pointer ][ 0 ] ) {
- case DIFF_INSERT:
- countInsert++;
- textInsert += diffs[ pointer ][ 1 ];
- break;
- case DIFF_DELETE:
- countDelete++;
- textDelete += diffs[ pointer ][ 1 ];
- break;
- case DIFF_EQUAL:
- // Upon reaching an equality, check for prior redundancies.
- if ( countDelete >= 1 && countInsert >= 1 ) {
- // Delete the offending records and add the merged ones.
- diffs.splice( pointer - countDelete - countInsert,
- countDelete + countInsert );
- pointer = pointer - countDelete - countInsert;
- a = this.DiffMain( textDelete, textInsert, false, deadline );
- for ( j = a.length - 1; j >= 0; j-- ) {
- diffs.splice( pointer, 0, a[ j ] );
- }
- pointer = pointer + a.length;
- }
- countInsert = 0;
- countDelete = 0;
- textDelete = "";
- textInsert = "";
- break;
- }
- pointer++;
- }
- diffs.pop(); // Remove the dummy entry at the end.
-
- return diffs;
- };
-
- /**
- * Find the 'middle snake' of a diff, split the problem in two
- * and return the recursively constructed diff.
- * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @param {number} deadline Time at which to bail if not yet complete.
- * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
- * @private
- */
- DiffMatchPatch.prototype.diffBisect = function( text1, text2, deadline ) {
- var text1Length, text2Length, maxD, vOffset, vLength,
- v1, v2, x, delta, front, k1start, k1end, k2start,
- k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2;
- // Cache the text lengths to prevent multiple calls.
- text1Length = text1.length;
- text2Length = text2.length;
- maxD = Math.ceil( ( text1Length + text2Length ) / 2 );
- vOffset = maxD;
- vLength = 2 * maxD;
- v1 = new Array( vLength );
- v2 = new Array( vLength );
- // Setting all elements to -1 is faster in Chrome & Firefox than mixing
- // integers and undefined.
- for ( x = 0; x < vLength; x++ ) {
- v1[ x ] = -1;
- v2[ x ] = -1;
- }
- v1[ vOffset + 1 ] = 0;
- v2[ vOffset + 1 ] = 0;
- delta = text1Length - text2Length;
- // If the total number of characters is odd, then the front path will collide
- // with the reverse path.
- front = ( delta % 2 !== 0 );
- // Offsets for start and end of k loop.
- // Prevents mapping of space beyond the grid.
- k1start = 0;
- k1end = 0;
- k2start = 0;
- k2end = 0;
- for ( d = 0; d < maxD; d++ ) {
- // Bail out if deadline is reached.
- if ( ( new Date() ).getTime() > deadline ) {
- break;
- }
-
- // Walk the front path one step.
- for ( k1 = -d + k1start; k1 <= d - k1end; k1 += 2 ) {
- k1Offset = vOffset + k1;
- if ( k1 === -d || ( k1 !== d && v1[ k1Offset - 1 ] < v1[ k1Offset + 1 ] ) ) {
- x1 = v1[ k1Offset + 1 ];
- } else {
- x1 = v1[ k1Offset - 1 ] + 1;
- }
- y1 = x1 - k1;
- while ( x1 < text1Length && y1 < text2Length &&
- text1.charAt( x1 ) === text2.charAt( y1 ) ) {
- x1++;
- y1++;
- }
- v1[ k1Offset ] = x1;
- if ( x1 > text1Length ) {
- // Ran off the right of the graph.
- k1end += 2;
- } else if ( y1 > text2Length ) {
- // Ran off the bottom of the graph.
- k1start += 2;
- } else if ( front ) {
- k2Offset = vOffset + delta - k1;
- if ( k2Offset >= 0 && k2Offset < vLength && v2[ k2Offset ] !== -1 ) {
- // Mirror x2 onto top-left coordinate system.
- x2 = text1Length - v2[ k2Offset ];
- if ( x1 >= x2 ) {
- // Overlap detected.
- return this.diffBisectSplit( text1, text2, x1, y1, deadline );
- }
- }
- }
- }
-
- // Walk the reverse path one step.
- for ( k2 = -d + k2start; k2 <= d - k2end; k2 += 2 ) {
- k2Offset = vOffset + k2;
- if ( k2 === -d || ( k2 !== d && v2[ k2Offset - 1 ] < v2[ k2Offset + 1 ] ) ) {
- x2 = v2[ k2Offset + 1 ];
- } else {
- x2 = v2[ k2Offset - 1 ] + 1;
- }
- y2 = x2 - k2;
- while ( x2 < text1Length && y2 < text2Length &&
- text1.charAt( text1Length - x2 - 1 ) ===
- text2.charAt( text2Length - y2 - 1 ) ) {
- x2++;
- y2++;
- }
- v2[ k2Offset ] = x2;
- if ( x2 > text1Length ) {
- // Ran off the left of the graph.
- k2end += 2;
- } else if ( y2 > text2Length ) {
- // Ran off the top of the graph.
- k2start += 2;
- } else if ( !front ) {
- k1Offset = vOffset + delta - k2;
- if ( k1Offset >= 0 && k1Offset < vLength && v1[ k1Offset ] !== -1 ) {
- x1 = v1[ k1Offset ];
- y1 = vOffset + x1 - k1Offset;
- // Mirror x2 onto top-left coordinate system.
- x2 = text1Length - x2;
- if ( x1 >= x2 ) {
- // Overlap detected.
- return this.diffBisectSplit( text1, text2, x1, y1, deadline );
- }
- }
- }
- }
- }
- // Diff took too long and hit the deadline or
- // number of diffs equals number of characters, no commonality at all.
- return [
- [ DIFF_DELETE, text1 ],
- [ DIFF_INSERT, text2 ]
- ];
- };
-
- /**
- * Given the location of the 'middle snake', split the diff in two parts
- * and recurse.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @param {number} x Index of split point in text1.
- * @param {number} y Index of split point in text2.
- * @param {number} deadline Time at which to bail if not yet complete.
- * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
- * @private
- */
- DiffMatchPatch.prototype.diffBisectSplit = function( text1, text2, x, y, deadline ) {
- var text1a, text1b, text2a, text2b, diffs, diffsb;
- text1a = text1.substring( 0, x );
- text2a = text2.substring( 0, y );
- text1b = text1.substring( x );
- text2b = text2.substring( y );
-
- // Compute both diffs serially.
- diffs = this.DiffMain( text1a, text2a, false, deadline );
- diffsb = this.DiffMain( text1b, text2b, false, deadline );
-
- return diffs.concat( diffsb );
- };
-
- /**
- * Reduce the number of edits by eliminating semantically trivial equalities.
- * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
- */
- DiffMatchPatch.prototype.diffCleanupSemantic = function( diffs ) {
- var changes, equalities, equalitiesLength, lastequality,
- pointer, lengthInsertions2, lengthDeletions2, lengthInsertions1,
- lengthDeletions1, deletion, insertion, overlapLength1, overlapLength2;
- changes = false;
- equalities = []; // Stack of indices where equalities are found.
- equalitiesLength = 0; // Keeping our own length var is faster in JS.
- /** @type {?string} */
- lastequality = null;
- // Always equal to diffs[equalities[equalitiesLength - 1]][1]
- pointer = 0; // Index of current position.
- // Number of characters that changed prior to the equality.
- lengthInsertions1 = 0;
- lengthDeletions1 = 0;
- // Number of characters that changed after the equality.
- lengthInsertions2 = 0;
- lengthDeletions2 = 0;
- while ( pointer < diffs.length ) {
- if ( diffs[ pointer ][ 0 ] === DIFF_EQUAL ) { // Equality found.
- equalities[ equalitiesLength++ ] = pointer;
- lengthInsertions1 = lengthInsertions2;
- lengthDeletions1 = lengthDeletions2;
- lengthInsertions2 = 0;
- lengthDeletions2 = 0;
- lastequality = diffs[ pointer ][ 1 ];
- } else { // An insertion or deletion.
- if ( diffs[ pointer ][ 0 ] === DIFF_INSERT ) {
- lengthInsertions2 += diffs[ pointer ][ 1 ].length;
- } else {
- lengthDeletions2 += diffs[ pointer ][ 1 ].length;
- }
- // Eliminate an equality that is smaller or equal to the edits on both
- // sides of it.
- if ( lastequality && ( lastequality.length <=
- Math.max( lengthInsertions1, lengthDeletions1 ) ) &&
- ( lastequality.length <= Math.max( lengthInsertions2,
- lengthDeletions2 ) ) ) {
-
- // Duplicate record.
- diffs.splice(
- equalities[ equalitiesLength - 1 ],
- 0,
- [ DIFF_DELETE, lastequality ]
- );
-
- // Change second copy to insert.
- diffs[ equalities[ equalitiesLength - 1 ] + 1 ][ 0 ] = DIFF_INSERT;
-
- // Throw away the equality we just deleted.
- equalitiesLength--;
-
- // Throw away the previous equality (it needs to be reevaluated).
- equalitiesLength--;
- pointer = equalitiesLength > 0 ? equalities[ equalitiesLength - 1 ] : -1;
-
- // Reset the counters.
- lengthInsertions1 = 0;
- lengthDeletions1 = 0;
- lengthInsertions2 = 0;
- lengthDeletions2 = 0;
- lastequality = null;
- changes = true;
- }
- }
- pointer++;
- }
-
- // Normalize the diff.
- if ( changes ) {
- this.diffCleanupMerge( diffs );
- }
-
- // Find any overlaps between deletions and insertions.
- // e.g: <del>abcxxx</del><ins>xxxdef</ins>
- // -> <del>abc</del>xxx<ins>def</ins>
- // e.g: <del>xxxabc</del><ins>defxxx</ins>
- // -> <ins>def</ins>xxx<del>abc</del>
- // Only extract an overlap if it is as big as the edit ahead or behind it.
- pointer = 1;
- while ( pointer < diffs.length ) {
- if ( diffs[ pointer - 1 ][ 0 ] === DIFF_DELETE &&
- diffs[ pointer ][ 0 ] === DIFF_INSERT ) {
- deletion = diffs[ pointer - 1 ][ 1 ];
- insertion = diffs[ pointer ][ 1 ];
- overlapLength1 = this.diffCommonOverlap( deletion, insertion );
- overlapLength2 = this.diffCommonOverlap( insertion, deletion );
- if ( overlapLength1 >= overlapLength2 ) {
- if ( overlapLength1 >= deletion.length / 2 ||
- overlapLength1 >= insertion.length / 2 ) {
- // Overlap found. Insert an equality and trim the surrounding edits.
- diffs.splice(
- pointer,
- 0,
- [ DIFF_EQUAL, insertion.substring( 0, overlapLength1 ) ]
- );
- diffs[ pointer - 1 ][ 1 ] =
- deletion.substring( 0, deletion.length - overlapLength1 );
- diffs[ pointer + 1 ][ 1 ] = insertion.substring( overlapLength1 );
- pointer++;
- }
- } else {
- if ( overlapLength2 >= deletion.length / 2 ||
- overlapLength2 >= insertion.length / 2 ) {
-
- // Reverse overlap found.
- // Insert an equality and swap and trim the surrounding edits.
- diffs.splice(
- pointer,
- 0,
- [ DIFF_EQUAL, deletion.substring( 0, overlapLength2 ) ]
- );
-
- diffs[ pointer - 1 ][ 0 ] = DIFF_INSERT;
- diffs[ pointer - 1 ][ 1 ] =
- insertion.substring( 0, insertion.length - overlapLength2 );
- diffs[ pointer + 1 ][ 0 ] = DIFF_DELETE;
- diffs[ pointer + 1 ][ 1 ] =
- deletion.substring( overlapLength2 );
- pointer++;
- }
- }
- pointer++;
- }
- pointer++;
- }
- };
-
- /**
- * Determine if the suffix of one string is the prefix of another.
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {number} The number of characters common to the end of the first
- * string and the start of the second string.
- * @private
- */
- DiffMatchPatch.prototype.diffCommonOverlap = function( text1, text2 ) {
- var text1Length, text2Length, textLength,
- best, length, pattern, found;
- // Cache the text lengths to prevent multiple calls.
- text1Length = text1.length;
- text2Length = text2.length;
- // Eliminate the null case.
- if ( text1Length === 0 || text2Length === 0 ) {
- return 0;
- }
- // Truncate the longer string.
- if ( text1Length > text2Length ) {
- text1 = text1.substring( text1Length - text2Length );
- } else if ( text1Length < text2Length ) {
- text2 = text2.substring( 0, text1Length );
- }
- textLength = Math.min( text1Length, text2Length );
- // Quick check for the worst case.
- if ( text1 === text2 ) {
- return textLength;
- }
-
- // Start by looking for a single character match
- // and increase length until no match is found.
- // Performance analysis: https://neil.fraser.name/news/2010/11/04/
- best = 0;
- length = 1;
- while ( true ) {
- pattern = text1.substring( textLength - length );
- found = text2.indexOf( pattern );
- if ( found === -1 ) {
- return best;
- }
- length += found;
- if ( found === 0 || text1.substring( textLength - length ) ===
- text2.substring( 0, length ) ) {
- best = length;
- length++;
- }
- }
- };
-
- /**
- * Split two texts into an array of strings. Reduce the texts to a string of
- * hashes where each Unicode character represents one line.
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
- * An object containing the encoded text1, the encoded text2 and
- * the array of unique strings.
- * The zeroth element of the array of unique strings is intentionally blank.
- * @private
- */
- DiffMatchPatch.prototype.diffLinesToChars = function( text1, text2 ) {
- var lineArray, lineHash, chars1, chars2;
- lineArray = []; // e.g. lineArray[4] === 'Hello\n'
- lineHash = {}; // e.g. lineHash['Hello\n'] === 4
-
- // '\x00' is a valid character, but various debuggers don't like it.
- // So we'll insert a junk entry to avoid generating a null character.
- lineArray[ 0 ] = "";
-
- /**
- * Split a text into an array of strings. Reduce the texts to a string of
- * hashes where each Unicode character represents one line.
- * Modifies linearray and linehash through being a closure.
- * @param {string} text String to encode.
- * @return {string} Encoded string.
- * @private
- */
- function diffLinesToCharsMunge( text ) {
- var chars, lineStart, lineEnd, lineArrayLength, line;
- chars = "";
- // Walk the text, pulling out a substring for each line.
- // text.split('\n') would would temporarily double our memory footprint.
- // Modifying text would create many large strings to garbage collect.
- lineStart = 0;
- lineEnd = -1;
- // Keeping our own length variable is faster than looking it up.
- lineArrayLength = lineArray.length;
- while ( lineEnd < text.length - 1 ) {
- lineEnd = text.indexOf( "\n", lineStart );
- if ( lineEnd === -1 ) {
- lineEnd = text.length - 1;
- }
- line = text.substring( lineStart, lineEnd + 1 );
- lineStart = lineEnd + 1;
-
- if ( lineHash.hasOwnProperty ? lineHash.hasOwnProperty( line ) :
- ( lineHash[ line ] !== undefined ) ) {
- chars += String.fromCharCode( lineHash[ line ] );
- } else {
- chars += String.fromCharCode( lineArrayLength );
- lineHash[ line ] = lineArrayLength;
- lineArray[ lineArrayLength++ ] = line;
- }
- }
- return chars;
- }
-
- chars1 = diffLinesToCharsMunge( text1 );
- chars2 = diffLinesToCharsMunge( text2 );
- return {
- chars1: chars1,
- chars2: chars2,
- lineArray: lineArray
- };
- };
-
- /**
- * Rehydrate the text in a diff from a string of line hashes to real lines of
- * text.
- * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
- * @param {!Array.<string>} lineArray Array of unique strings.
- * @private
- */
- DiffMatchPatch.prototype.diffCharsToLines = function( diffs, lineArray ) {
- var x, chars, text, y;
- for ( x = 0; x < diffs.length; x++ ) {
- chars = diffs[ x ][ 1 ];
- text = [];
- for ( y = 0; y < chars.length; y++ ) {
- text[ y ] = lineArray[ chars.charCodeAt( y ) ];
- }
- diffs[ x ][ 1 ] = text.join( "" );
- }
- };
-
- /**
- * Reorder and merge like edit sections. Merge equalities.
- * Any edit section can move as long as it doesn't cross an equality.
- * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
- */
- DiffMatchPatch.prototype.diffCleanupMerge = function( diffs ) {
- var pointer, countDelete, countInsert, textInsert, textDelete,
- commonlength, changes, diffPointer, position;
- diffs.push( [ DIFF_EQUAL, "" ] ); // Add a dummy entry at the end.
- pointer = 0;
- countDelete = 0;
- countInsert = 0;
- textDelete = "";
- textInsert = "";
- commonlength;
- while ( pointer < diffs.length ) {
- switch ( diffs[ pointer ][ 0 ] ) {
- case DIFF_INSERT:
- countInsert++;
- textInsert += diffs[ pointer ][ 1 ];
- pointer++;
- break;
- case DIFF_DELETE:
- countDelete++;
- textDelete += diffs[ pointer ][ 1 ];
- pointer++;
- break;
- case DIFF_EQUAL:
- // Upon reaching an equality, check for prior redundancies.
- if ( countDelete + countInsert > 1 ) {
- if ( countDelete !== 0 && countInsert !== 0 ) {
- // Factor out any common prefixes.
- commonlength = this.diffCommonPrefix( textInsert, textDelete );
- if ( commonlength !== 0 ) {
- if ( ( pointer - countDelete - countInsert ) > 0 &&
- diffs[ pointer - countDelete - countInsert - 1 ][ 0 ] ===
- DIFF_EQUAL ) {
- diffs[ pointer - countDelete - countInsert - 1 ][ 1 ] +=
- textInsert.substring( 0, commonlength );
- } else {
- diffs.splice( 0, 0, [ DIFF_EQUAL,
- textInsert.substring( 0, commonlength )
- ] );
- pointer++;
- }
- textInsert = textInsert.substring( commonlength );
- textDelete = textDelete.substring( commonlength );
- }
- // Factor out any common suffixies.
- commonlength = this.diffCommonSuffix( textInsert, textDelete );
- if ( commonlength !== 0 ) {
- diffs[ pointer ][ 1 ] = textInsert.substring( textInsert.length -
- commonlength ) + diffs[ pointer ][ 1 ];
- textInsert = textInsert.substring( 0, textInsert.length -
- commonlength );
- textDelete = textDelete.substring( 0, textDelete.length -
- commonlength );
- }
- }
- // Delete the offending records and add the merged ones.
- if ( countDelete === 0 ) {
- diffs.splice( pointer - countInsert,
- countDelete + countInsert, [ DIFF_INSERT, textInsert ] );
- } else if ( countInsert === 0 ) {
- diffs.splice( pointer - countDelete,
- countDelete + countInsert, [ DIFF_DELETE, textDelete ] );
- } else {
- diffs.splice(
- pointer - countDelete - countInsert,
- countDelete + countInsert,
- [ DIFF_DELETE, textDelete ], [ DIFF_INSERT, textInsert ]
- );
- }
- pointer = pointer - countDelete - countInsert +
- ( countDelete ? 1 : 0 ) + ( countInsert ? 1 : 0 ) + 1;
- } else if ( pointer !== 0 && diffs[ pointer - 1 ][ 0 ] === DIFF_EQUAL ) {
-
- // Merge this equality with the previous one.
- diffs[ pointer - 1 ][ 1 ] += diffs[ pointer ][ 1 ];
- diffs.splice( pointer, 1 );
- } else {
- pointer++;
- }
- countInsert = 0;
- countDelete = 0;
- textDelete = "";
- textInsert = "";
- break;
- }
- }
- if ( diffs[ diffs.length - 1 ][ 1 ] === "" ) {
- diffs.pop(); // Remove the dummy entry at the end.
- }
-
- // Second pass: look for single edits surrounded on both sides by equalities
- // which can be shifted sideways to eliminate an equality.
- // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
- changes = false;
- pointer = 1;
-
- // Intentionally ignore the first and last element (don't need checking).
- while ( pointer < diffs.length - 1 ) {
- if ( diffs[ pointer - 1 ][ 0 ] === DIFF_EQUAL &&
- diffs[ pointer + 1 ][ 0 ] === DIFF_EQUAL ) {
-
- diffPointer = diffs[ pointer ][ 1 ];
- position = diffPointer.substring(
- diffPointer.length - diffs[ pointer - 1 ][ 1 ].length
- );
-
- // This is a single edit surrounded by equalities.
- if ( position === diffs[ pointer - 1 ][ 1 ] ) {
-
- // Shift the edit over the previous equality.
- diffs[ pointer ][ 1 ] = diffs[ pointer - 1 ][ 1 ] +
- diffs[ pointer ][ 1 ].substring( 0, diffs[ pointer ][ 1 ].length -
- diffs[ pointer - 1 ][ 1 ].length );
- diffs[ pointer + 1 ][ 1 ] =
- diffs[ pointer - 1 ][ 1 ] + diffs[ pointer + 1 ][ 1 ];
- diffs.splice( pointer - 1, 1 );
- changes = true;
- } else if ( diffPointer.substring( 0, diffs[ pointer + 1 ][ 1 ].length ) ===
- diffs[ pointer + 1 ][ 1 ] ) {
-
- // Shift the edit over the next equality.
- diffs[ pointer - 1 ][ 1 ] += diffs[ pointer + 1 ][ 1 ];
- diffs[ pointer ][ 1 ] =
- diffs[ pointer ][ 1 ].substring( diffs[ pointer + 1 ][ 1 ].length ) +
- diffs[ pointer + 1 ][ 1 ];
- diffs.splice( pointer + 1, 1 );
- changes = true;
- }
- }
- pointer++;
- }
- // If shifts were made, the diff needs reordering and another shift sweep.
- if ( changes ) {
- this.diffCleanupMerge( diffs );
- }
- };
-
- return function( o, n ) {
- var diff, output, text;
- diff = new DiffMatchPatch();
- output = diff.DiffMain( o, n );
- diff.diffCleanupEfficiency( output );
- text = diff.diffPrettyHtml( output );
-
- return text;
- };
-}() );
-
-// Get a reference to the global object, like window in browsers
-}( (function() {
- return this;
-})() ));
-
-(function() {
-
-// Don't load the HTML Reporter on non-Browser environments
-if ( typeof window === "undefined" || !window.document ) {
- return;
-}
-
-// Deprecated QUnit.init - Ref #530
-// Re-initialize the configuration options
-QUnit.init = function() {
- var tests, banner, result, qunit,
- config = QUnit.config;
-
- config.stats = { all: 0, bad: 0 };
- config.moduleStats = { all: 0, bad: 0 };
- config.started = 0;
- config.updateRate = 1000;
- config.blocking = false;
- config.autostart = true;
- config.autorun = false;
- config.filter = "";
- config.queue = [];
-
- // Return on non-browser environments
- // This is necessary to not break on node tests
- if ( typeof window === "undefined" ) {
- return;
- }
-
- qunit = id( "qunit" );
- if ( qunit ) {
- qunit.innerHTML =
- "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
- "<h2 id='qunit-banner'></h2>" +
- "<div id='qunit-testrunner-toolbar'></div>" +
- "<h2 id='qunit-userAgent'></h2>" +
- "<ol id='qunit-tests'></ol>";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...<br /> ";
- }
-};
-
-var config = QUnit.config,
- collapseNext = false,
- hasOwn = Object.prototype.hasOwnProperty,
- defined = {
- document: window.document !== undefined,
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch ( e ) {
- return false;
- }
- }())
- },
- modulesList = [];
-
-/**
-* Escape text for attribute or text content.
-*/
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
-
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch ( s ) {
- case "'":
- return "'";
- case "\"":
- return """;
- case "<":
- return "<";
- case ">":
- return ">";
- case "&":
- return "&";
- }
- });
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- if ( elem.addEventListener ) {
-
- // Standards-based browsers
- elem.addEventListener( type, fn, false );
- } else if ( elem.attachEvent ) {
-
- // support: IE <9
- elem.attachEvent( "on" + type, function() {
- var event = window.event;
- if ( !event.target ) {
- event.target = event.srcElement || document;
- }
-
- fn.call( elem, event );
- });
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[ i ], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += ( elem.className ? " " : "" ) + name;
- }
-}
-
-function toggleClass( elem, name ) {
- if ( hasClass( elem, name ) ) {
- removeClass( elem, name );
- } else {
- addClass( elem, name );
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
-
- // Class name may appear multiple times
- while ( set.indexOf( " " + name + " " ) >= 0 ) {
- set = set.replace( " " + name + " ", " " );
- }
-
- // trim for prettiness
- elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" );
-}
-
-function id( name ) {
- return defined.document && document.getElementById && document.getElementById( name );
-}
-
-function getUrlConfigHtml() {
- var i, j, val,
- escaped, escapedTooltip,
- selection = false,
- len = config.urlConfig.length,
- urlConfigHtml = "";
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[ i ];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val
- };
- }
-
- escaped = escapeText( val.id );
- escapedTooltip = escapeText( val.tooltip );
-
- if ( config[ val.id ] === undefined ) {
- config[ val.id ] = QUnit.urlParams[ val.id ];
- }
-
- if ( !val.value || typeof val.value === "string" ) {
- urlConfigHtml += "<input id='qunit-urlconfig-" + escaped +
- "' name='" + escaped + "' type='checkbox'" +
- ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
- ( config[ val.id ] ? " checked='checked'" : "" ) +
- " title='" + escapedTooltip + "' /><label for='qunit-urlconfig-" + escaped +
- "' title='" + escapedTooltip + "'>" + val.label + "</label>";
- } else {
- urlConfigHtml += "<label for='qunit-urlconfig-" + escaped +
- "' title='" + escapedTooltip + "'>" + val.label +
- ": </label><select id='qunit-urlconfig-" + escaped +
- "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>";
-
- if ( QUnit.is( "array", val.value ) ) {
- for ( j = 0; j < val.value.length; j++ ) {
- escaped = escapeText( val.value[ j ] );
- urlConfigHtml += "<option value='" + escaped + "'" +
- ( config[ val.id ] === val.value[ j ] ?
- ( selection = true ) && " selected='selected'" : "" ) +
- ">" + escaped + "</option>";
- }
- } else {
- for ( j in val.value ) {
- if ( hasOwn.call( val.value, j ) ) {
- urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
- ( config[ val.id ] === j ?
- ( selection = true ) && " selected='selected'" : "" ) +
- ">" + escapeText( val.value[ j ] ) + "</option>";
- }
- }
- }
- if ( config[ val.id ] && !selection ) {
- escaped = escapeText( config[ val.id ] );
- urlConfigHtml += "<option value='" + escaped +
- "' selected='selected' disabled='disabled'>" + escaped + "</option>";
- }
- urlConfigHtml += "</select>";
- }
- }
-
- return urlConfigHtml;
-}
-
-// Handle "click" events on toolbar checkboxes and "change" for select menus.
-// Updates the URL with the new state of `config.urlConfig` values.
-function toolbarChanged() {
- var updatedUrl, value,
- field = this,
- params = {};
-
- // Detect if field is a select menu or a checkbox
- if ( "selectedIndex" in field ) {
- value = field.options[ field.selectedIndex ].value || undefined;
- } else {
- value = field.checked ? ( field.defaultValue || true ) : undefined;
- }
-
- params[ field.name ] = value;
- updatedUrl = setUrl( params );
-
- if ( "hidepassed" === field.name && "replaceState" in window.history ) {
- config[ field.name ] = value || false;
- if ( value ) {
- addClass( id( "qunit-tests" ), "hidepass" );
- } else {
- removeClass( id( "qunit-tests" ), "hidepass" );
- }
-
- // It is not necessary to refresh the whole page
- window.history.replaceState( null, "", updatedUrl );
- } else {
- window.location = updatedUrl;
- }
-}
-
-function setUrl( params ) {
- var key,
- querystring = "?";
-
- params = QUnit.extend( QUnit.extend( {}, QUnit.urlParams ), params );
-
- for ( key in params ) {
- if ( hasOwn.call( params, key ) ) {
- if ( params[ key ] === undefined ) {
- continue;
- }
- querystring += encodeURIComponent( key );
- if ( params[ key ] !== true ) {
- querystring += "=" + encodeURIComponent( params[ key ] );
- }
- querystring += "&";
- }
- }
- return location.protocol + "//" + location.host +
- location.pathname + querystring.slice( 0, -1 );
-}
-
-function applyUrlParams() {
- var selectedModule,
- modulesList = id( "qunit-modulefilter" ),
- filter = id( "qunit-filter-input" ).value;
-
- selectedModule = modulesList ?
- decodeURIComponent( modulesList.options[ modulesList.selectedIndex ].value ) :
- undefined;
-
- window.location = setUrl({
- module: ( selectedModule === "" ) ? undefined : selectedModule,
- filter: ( filter === "" ) ? undefined : filter,
-
- // Remove testId filter
- testId: undefined
- });
-}
-
-function toolbarUrlConfigContainer() {
- var urlConfigContainer = document.createElement( "span" );
-
- urlConfigContainer.innerHTML = getUrlConfigHtml();
- addClass( urlConfigContainer, "qunit-url-config" );
-
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change" for checkboxes
- addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged );
- addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged );
-
- return urlConfigContainer;
-}
-
-function toolbarLooseFilter() {
- var filter = document.createElement( "form" ),
- label = document.createElement( "label" ),
- input = document.createElement( "input" ),
- button = document.createElement( "button" );
-
- addClass( filter, "qunit-filter" );
-
- label.innerHTML = "Filter: ";
-
- input.type = "text";
- input.value = config.filter || "";
- input.name = "filter";
- input.id = "qunit-filter-input";
-
- button.innerHTML = "Go";
-
- label.appendChild( input );
-
- filter.appendChild( label );
- filter.appendChild( button );
- addEvent( filter, "submit", function( ev ) {
- applyUrlParams();
-
- if ( ev && ev.preventDefault ) {
- ev.preventDefault();
- }
-
- return false;
- });
-
- return filter;
-}
-
-function toolbarModuleFilterHtml() {
- var i,
- moduleFilterHtml = "";
-
- if ( !modulesList.length ) {
- return false;
- }
-
- modulesList.sort(function( a, b ) {
- return a.localeCompare( b );
- });
-
- moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" +
- "<select id='qunit-modulefilter' name='modulefilter'><option value='' " +
- ( QUnit.urlParams.module === undefined ? "selected='selected'" : "" ) +
- ">< All Modules ></option>";
-
- for ( i = 0; i < modulesList.length; i++ ) {
- moduleFilterHtml += "<option value='" +
- escapeText( encodeURIComponent( modulesList[ i ] ) ) + "' " +
- ( QUnit.urlParams.module === modulesList[ i ] ? "selected='selected'" : "" ) +
- ">" + escapeText( modulesList[ i ] ) + "</option>";
- }
- moduleFilterHtml += "</select>";
-
- return moduleFilterHtml;
-}
-
-function toolbarModuleFilter() {
- var toolbar = id( "qunit-testrunner-toolbar" ),
- moduleFilter = document.createElement( "span" ),
- moduleFilterHtml = toolbarModuleFilterHtml();
-
- if ( !toolbar || !moduleFilterHtml ) {
- return false;
- }
-
- moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
- moduleFilter.innerHTML = moduleFilterHtml;
-
- addEvent( moduleFilter.lastChild, "change", applyUrlParams );
-
- toolbar.appendChild( moduleFilter );
-}
-
-function appendToolbar() {
- var toolbar = id( "qunit-testrunner-toolbar" );
-
- if ( toolbar ) {
- toolbar.appendChild( toolbarUrlConfigContainer() );
- toolbar.appendChild( toolbarLooseFilter() );
- }
-}
-
-function appendHeader() {
- var header = id( "qunit-header" );
-
- if ( header ) {
- header.innerHTML = "<a href='" +
- setUrl({ filter: undefined, module: undefined, testId: undefined }) +
- "'>" + header.innerHTML + "</a> ";
- }
-}
-
-function appendBanner() {
- var banner = id( "qunit-banner" );
-
- if ( banner ) {
- banner.className = "";
- }
-}
-
-function appendTestResults() {
- var tests = id( "qunit-tests" ),
- result = id( "qunit-testresult" );
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- tests.innerHTML = "";
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...<br /> ";
- }
-}
-
-function storeFixture() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- config.fixture = fixture.innerHTML;
- }
-}
-
-function appendFilteredTest() {
- var testId = QUnit.config.testId;
- if ( !testId || testId.length <= 0 ) {
- return "";
- }
- return "<div id='qunit-filteredTest'>Rerunning selected tests: " + testId.join(", ") +
- " <a id='qunit-clearFilter' href='" +
- setUrl({ filter: undefined, module: undefined, testId: undefined }) +
- "'>" + "Run all tests" + "</a></div>";
-}
-
-function appendUserAgent() {
- var userAgent = id( "qunit-userAgent" );
-
- if ( userAgent ) {
- userAgent.innerHTML = "";
- userAgent.appendChild(
- document.createTextNode(
- "QUnit " + QUnit.version + "; " + navigator.userAgent
- )
- );
- }
-}
-
-function appendTestsList( modules ) {
- var i, l, x, z, test, moduleObj;
-
- for ( i = 0, l = modules.length; i < l; i++ ) {
- moduleObj = modules[ i ];
-
- if ( moduleObj.name ) {
- modulesList.push( moduleObj.name );
- }
-
- for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) {
- test = moduleObj.tests[ x ];
-
- appendTest( test.name, test.testId, moduleObj.name );
- }
- }
-}
-
-function appendTest( name, testId, moduleName ) {
- var title, rerunTrigger, testBlock, assertList,
- tests = id( "qunit-tests" );
-
- if ( !tests ) {
- return;
- }
-
- title = document.createElement( "strong" );
- title.innerHTML = getNameHtml( name, moduleName );
-
- rerunTrigger = document.createElement( "a" );
- rerunTrigger.innerHTML = "Rerun";
- rerunTrigger.href = setUrl({ testId: testId });
-
- testBlock = document.createElement( "li" );
- testBlock.appendChild( title );
- testBlock.appendChild( rerunTrigger );
- testBlock.id = "qunit-test-output-" + testId;
-
- assertList = document.createElement( "ol" );
- assertList.className = "qunit-assert-list";
-
- testBlock.appendChild( assertList );
-
- tests.appendChild( testBlock );
-}
-
-// HTML Reporter initialization and load
-QUnit.begin(function( details ) {
- var qunit = id( "qunit" );
-
- // Fixture is the only one necessary to run without the #qunit element
- storeFixture();
-
- if ( qunit ) {
- qunit.innerHTML =
- "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
- "<h2 id='qunit-banner'></h2>" +
- "<div id='qunit-testrunner-toolbar'></div>" +
- appendFilteredTest() +
- "<h2 id='qunit-userAgent'></h2>" +
- "<ol id='qunit-tests'></ol>";
- }
-
- appendHeader();
- appendBanner();
- appendTestResults();
- appendUserAgent();
- appendToolbar();
- appendTestsList( details.modules );
- toolbarModuleFilter();
-
- if ( qunit && config.hidepassed ) {
- addClass( qunit.lastChild, "hidepass" );
- }
-});
-
-QUnit.done(function( details ) {
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- html = [
- "Tests completed in ",
- details.runtime,
- " milliseconds.<br />",
- "<span class='passed'>",
- details.passed,
- "</span> assertions of <span class='total'>",
- details.total,
- "</span> passed, <span class='failed'>",
- details.failed,
- "</span> failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = details.failed ? "qunit-fail" : "qunit-pass";
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && defined.document && document.title ) {
-
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( details.failed ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && details.failed === 0 ) {
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( config.scrolltop && window.scrollTo ) {
- window.scrollTo( 0, 0 );
- }
-});
-
-function getNameHtml( name, module ) {
- var nameHtml = "";
-
- if ( module ) {
- nameHtml = "<span class='module-name'>" + escapeText( module ) + "</span>: ";
- }
-
- nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>";
-
- return nameHtml;
-}
-
-QUnit.testStart(function( details ) {
- var running, testBlock, bad;
-
- testBlock = id( "qunit-test-output-" + details.testId );
- if ( testBlock ) {
- testBlock.className = "running";
- } else {
-
- // Report later registered tests
- appendTest( details.name, details.testId, details.module );
- }
-
- running = id( "qunit-testresult" );
- if ( running ) {
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + details.module + "-" + details.name );
-
- running.innerHTML = ( bad ?
- "Rerunning previously failed test: <br />" :
- "Running: <br />" ) +
- getNameHtml( details.name, details.module );
- }
-
-});
-
-function stripHtml( string ) {
- // strip tags, html entity and whitespaces
- return string.replace(/<\/?[^>]+(>|$)/g, "").replace(/\"/g, "").replace(/\s+/g, "");
-}
-
-QUnit.log(function( details ) {
- var assertList, assertLi,
- message, expected, actual, diff,
- showDiff = false,
- testItem = id( "qunit-test-output-" + details.testId );
-
- if ( !testItem ) {
- return;
- }
-
- message = escapeText( details.message ) || ( details.result ? "okay" : "failed" );
- message = "<span class='test-message'>" + message + "</span>";
- message += "<span class='runtime'>@ " + details.runtime + " ms</span>";
-
- // pushFailure doesn't provide details.expected
- // when it calls, it's implicit to also not show expected and diff stuff
- // Also, we need to check details.expected existence, as it can exist and be undefined
- if ( !details.result && hasOwn.call( details, "expected" ) ) {
- if ( details.negative ) {
- expected = escapeText( "NOT " + QUnit.dump.parse( details.expected ) );
- } else {
- expected = escapeText( QUnit.dump.parse( details.expected ) );
- }
-
- actual = escapeText( QUnit.dump.parse( details.actual ) );
- message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" +
- expected +
- "</pre></td></tr>";
-
- if ( actual !== expected ) {
-
- message += "<tr class='test-actual'><th>Result: </th><td><pre>" +
- actual + "</pre></td></tr>";
-
- // Don't show diff if actual or expected are booleans
- if ( !( /^(true|false)$/.test( actual ) ) &&
- !( /^(true|false)$/.test( expected ) ) ) {
- diff = QUnit.diff( expected, actual );
- showDiff = stripHtml( diff ).length !==
- stripHtml( expected ).length +
- stripHtml( actual ).length;
- }
-
- // Don't show diff if expected and actual are totally different
- if ( showDiff ) {
- message += "<tr class='test-diff'><th>Diff: </th><td><pre>" +
- diff + "</pre></td></tr>";
- }
- } else if ( expected.indexOf( "[object Array]" ) !== -1 ||
- expected.indexOf( "[object Object]" ) !== -1 ) {
- message += "<tr class='test-message'><th>Message: </th><td>" +
- "Diff suppressed as the depth of object is more than current max depth (" +
- QUnit.config.maxDepth + ").<p>Hint: Use <code>QUnit.dump.maxDepth</code> to " +
- " run with a higher max depth or <a href='" + setUrl({ maxDepth: -1 }) + "'>" +
- "Rerun</a> without max depth.</p></td></tr>";
- }
-
- if ( details.source ) {
- message += "<tr class='test-source'><th>Source: </th><td><pre>" +
- escapeText( details.source ) + "</pre></td></tr>";
- }
-
- message += "</table>";
-
- // this occurs when pushFailure is set and we have an extracted stack trace
- } else if ( !details.result && details.source ) {
- message += "<table>" +
- "<tr class='test-source'><th>Source: </th><td><pre>" +
- escapeText( details.source ) + "</pre></td></tr>" +
- "</table>";
- }
-
- assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
-
- assertLi = document.createElement( "li" );
- assertLi.className = details.result ? "pass" : "fail";
- assertLi.innerHTML = message;
- assertList.appendChild( assertLi );
-});
-
-QUnit.testDone(function( details ) {
- var testTitle, time, testItem, assertList,
- good, bad, testCounts, skipped, sourceName,
- tests = id( "qunit-tests" );
-
- if ( !tests ) {
- return;
- }
-
- testItem = id( "qunit-test-output-" + details.testId );
-
- assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
-
- good = details.passed;
- bad = details.failed;
-
- // store result when possible
- if ( config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name );
- }
- }
-
- if ( bad === 0 ) {
-
- // Collapse the passing tests
- addClass( assertList, "qunit-collapsed" );
- } else if ( bad && config.collapse && !collapseNext ) {
-
- // Skip collapsing the first failing test
- collapseNext = true;
- } else {
-
- // Collapse remaining tests
- addClass( assertList, "qunit-collapsed" );
- }
-
- // testItem.firstChild is the test name
- testTitle = testItem.firstChild;
-
- testCounts = bad ?
- "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " :
- "";
-
- testTitle.innerHTML += " <b class='counts'>(" + testCounts +
- details.assertions.length + ")</b>";
-
- if ( details.skipped ) {
- testItem.className = "skipped";
- skipped = document.createElement( "em" );
- skipped.className = "qunit-skipped-label";
- skipped.innerHTML = "skipped";
- testItem.insertBefore( skipped, testTitle );
- } else {
- addEvent( testTitle, "click", function() {
- toggleClass( assertList, "qunit-collapsed" );
- });
-
- testItem.className = bad ? "fail" : "pass";
-
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = details.runtime + " ms";
- testItem.insertBefore( time, assertList );
- }
-
- // Show the source of the test when showing assertions
- if ( details.source ) {
- sourceName = document.createElement( "p" );
- sourceName.innerHTML = "<strong>Source: </strong>" + details.source;
- addClass( sourceName, "qunit-source" );
- if ( bad === 0 ) {
- addClass( sourceName, "qunit-collapsed" );
- }
- addEvent( testTitle, "click", function() {
- toggleClass( sourceName, "qunit-collapsed" );
- });
- testItem.appendChild( sourceName );
- }
-});
-
-if ( defined.document ) {
-
- // Avoid readyState issue with phantomjs
- // Ref: #818
- var notPhantom = ( function( p ) {
- return !( p && p.version && p.version.major > 0 );
- } )( window.phantom );
-
- if ( notPhantom && document.readyState === "complete" ) {
- QUnit.load();
- } else {
- addEvent( window, "load", QUnit.load );
- }
-} else {
- config.pageLoaded = true;
- config.autorun = true;
-}
-
-})();
+++ /dev/null
-
-QUnit.module("Shaders", {
- setup : function() {
- QUnit.stop();
- var that = this;
- this.cb = function(e) {
- QUnit.ok(true, "Scene loaded");
- var iframe = document.getElementById('daliframe');
- that.doc = iframe.contentDocument || iframe.contentWindow.document;
- that.doc.Module.postDaliWrapperRun = function() {
- dali = that.doc.Module;
- QUnit.start();
- };
- };
- loadDocument("dali-page.html"+window.location.search, this.cb);
- },
- teardown : function() {
- var v = document.getElementById("daliframe");
- v.removeEventListener("load", this.cb, true);
- }
-});
-
-QUnit.test( "shader meta data", function( assert ) {
- var info = new dali.ShaderInfo();
-
- var vertex;
- var fragment;
-
- vertex = "\n" +
- "attribute mediump vec3 aPosition;\n" +
- "attribute mediump vec2 aTexCoord;\n" +
- "varying mediump vec2 vTexCoord;\n" +
- "uniform mediump vec3 uSize;\n" +
- "// uniform mediump vec3 unusedUniform;\n" +
- "uniform mediump mat4 uModelView;\n" +
- "uniform mediump mat4 uProjection;\n" +
- "\n" +
- "void main(void)\n" +
- "{\n" +
- " gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
- " gl_Position.xyz *= uSize;\n" +
- " vTexCoord = aTexCoord;\n" +
- "}\n";
-
- fragment = "precision mediump float;\n" +
- "\n" +
- "uniform sampler2D sTexture;\n" +
- "uniform mediump vec4 uMyColor; // {min:[0,0,0,0], max:[1,1,1,1]}\n" +
- "uniform mediump vec4 uColor;\n" +
- "varying mediump vec2 vTexCoord;\n" +
- "\n" +
- "void main()\n" +
- "{\n" +
- " gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * uMyColor;\n" +
- "}\n";
-
- var canvas = document.createElement("canvas");
- var meta = info.fromCompilation(canvas.getContext("webgl"), vertex, fragment);
-
- var uniforms = { uSize: 1,
- uModelView: 1,
- uProjection: 1,
- uMyColor: 1,
- uColor: 1
- };
-
- assert.ok(meta.hasError === false);
- var name;
- var metaUniformName;
- var found;
-
- for(name in uniforms) {
- found = false;
- for(metaUniformName in meta.uniforms) {
- if(metaUniformName === name) {
- found = true;
- break;
- }
- }
- assert.ok(found, "missing:" + name);
- }
-
- assert.ok(compareArrays(meta.uniformUISpec.uMyColor.min, [0, 0, 0, 0]));
- assert.ok(compareArrays(meta.uniformUISpec.uMyColor.max, [1, 1, 1, 1]));
-
-
- meta = info.fromRegEx(vertex, fragment);
-
- assert.ok(meta.hasError === false);
-
- for(name in uniforms) {
- found = false;
- for(metaUniformName in meta.uniforms) {
- if(metaUniformName === name) {
- found = true;
- break;
- }
- }
- assert.ok(found, "missing:" + name);
- }
-
- assert.ok(compareArrays(meta.uniformUISpec.uMyColor.min, [0, 0, 0, 0]));
- assert.ok(compareArrays(meta.uniformUISpec.uMyColor.max, [1, 1, 1, 1]));
-
-});
+++ /dev/null
-
-QUnit.module("Signals", {
- setup : function() {
- QUnit.stop();
- var that = this;
- this.cb = function(e) {
- QUnit.ok(true, "Scene loaded");
- var iframe = document.getElementById('daliframe');
- that.doc = iframe.contentDocument || iframe.contentWindow.document;
- that.doc.Module.postDaliWrapperRun = function() {
- dali = that.doc.Module;
- QUnit.start();
- };
- };
- loadDocument("dali-page.html"+window.location.search, this.cb);
- },
- teardown : function() {
- var v = document.getElementById("daliframe");
- v.removeEventListener("load", this.cb, true);
- }
-});
-
-QUnit.test( "hello test", function( assert ) {
- var done = false;
-
- function onStage() {
- done = true;
- }
-
- var actor = new dali.Actor();
- actor.parentOrigin = [0.5, 0.5, 0.5];
- actor.anchorPoint = [0.5, 0.5, 0.5];
- actor.text = "actor";
- actor.name = actor.text;
- actor.size = [100, 100, 1];
- actor.position = [0, 0, 10];
-
- actor.connect("onStage", onStage);
-
- dali.stage.add(actor);
-
- dali.updateFrame();
-
- assert.ok(done === true);
-
-});
+++ /dev/null
-var EPSILON = 0.005;
-
-function compareArrays(a, b) {
- "use strict";
- if (Array.isArray(a) && Array.isArray(b)) {
- if (a.length === b.length) {
- for (var i = 0, len = a.length; i < len; i++) {
- if (Array.isArray(a[i])) {
- if (Array.isArray(b[i])) {
- if (!compareArrays(a[i], b[i])) {
- return false;
- }
- } else {
- return false;
- }
- } else {
- if (typeof (a[i]) === "number") {
- if (typeof (b[i]) !== "number") {
- return false;
- } else {
- if (Math.abs(a[i]) > Math.abs(b[i]) + EPSILON ||
- Math.abs(a[i]) < Math.abs(b[i]) - EPSILON) {
- return false;
- }
- }
- } else {
- if (a[i] !== b[i]) {
- return false;
- }
- }
- }
- }
- return true;
- }
- }
- return false;
-}
-
-function collectByName(collection) {
- var root = dali.stage.getRootLayer();
- if (collection === undefined) {
- collection = {};
- }
- var op = function(actor) {
- if (actor.name) {
- collection[actor.name] = actor;
- }
- return true;
- };
-
- dali.debug.depthVisit(root, op, true);
-
- return collection;
-}
-
-function square(color, size) {
- var a = dali.createSolidColorActor(color, 0, [0, 0, 0, 1], 0);
- a.size = size;
- return a;
-}
-
-function threeSquares() {
- var root = dali.stage.getRootLayer();
-
- var a = square([1, 0, 0, 1], [200, 200, 0]);
- a.name = "red";
- a.position = [-100, 0, -20];
- root.add(a);
- a.delete();
-
- a = square([0, 1, 0, 1], [200, 200, 0]);
- a.name = "green";
- a.position = [0, -100, -10];
- root.add(a);
- a.delete();
-
- a = square([0, 0, 1, 1], [200, 200, 0]);
- a.name = "blue";
- a.position = [0, -100, 0];
- root.add(a);
- a.delete();
-
- // root.delete();
-}
-
-function clear() {
- var root = dali.stage.getRootLayer();
- var children = root.getChildren();
-
- for (var i = 0, len = children.length; i < len; i++) {
- root.remove(children[i]);
- children[i].delete(); // delete the wrapper
- }
- // root.delete(); // wrapper
-}
-
-var loadDocument = function(url, f) {
- var v = document.getElementById("daliframe");
- QUnit.ok(v, "Found frame.");
- v.addEventListener("load", f, true);
- v.src = url;
-};
+++ /dev/null
-
-QUnit.module("Views", {
- setup : function() {
- QUnit.stop();
- var that = this;
- this.cb = function(e) {
- QUnit.ok(true, "Scene loaded");
- var iframe = document.getElementById('daliframe');
- that.doc = iframe.contentDocument || iframe.contentWindow.document;
- that.doc.Module.postDaliWrapperRun = function() {
- dali = that.doc.Module;
- QUnit.start();
- };
- };
- loadDocument("dali-page.html"+window.location.search, this.cb);
- },
- teardown : function() {
- var v = document.getElementById("daliframe");
- v.removeEventListener("load", this.cb, true);
- }
-});
-
-function addOnScreenQuad(assert)
-{
- var halfQuadSize = 0.5;
-
- // using helper function to create property buffer
- var verts = dali.createPropertyBuffer( {format: [ ["aPosition", dali.PropertyType.VECTOR3],
- ["aCol", dali.PropertyType.VECTOR4] ],
- data: { "aPosition": [ [-halfQuadSize, -halfQuadSize, 0.0],
- [+halfQuadSize, -halfQuadSize, 0.0],
- [-halfQuadSize, +halfQuadSize, 0.0],
- [+halfQuadSize, +halfQuadSize, 0.0]
- ],
- "aCol": [ [0, 0, 0, 1],
- [1, 0, 1, 1],
- [0, 1, 0, 1],
- [1, 1, 1, 1]
- ]
- }
- });
-
- var indices = dali.createPropertyBuffer( { format: [ ["indices", dali.PropertyType.INTEGER]],
- data: { "indices": [0, 3, 1, 0, 2, 3] } } ) ;
-
- var geometry = new dali.Geometry();
-
- assert.ok(verts);
- assert.ok(indices);
- assert.ok(geometry);
-
- geometry.addVertexBuffer(verts);
- geometry.setIndexBuffer(indices);
-
- var vertex = "" +
- "attribute mediump vec3 aPosition;" +
- "attribute mediump vec4 aCol;" +
- "uniform mediump mat4 uMvpMatrix;" +
- "uniform mediump vec3 uSize;" +
- "uniform lowp vec4 uColor;" +
- "varying lowp vec4 vColor;" +
- "" +
- "void main()" +
- "{" +
- " vColor = aCol * uColor;" +
- " mediump vec4 vertexPosition = vec4(aPosition,1.0);" +
- " vertexPosition.xyz *= uSize;" +
- " gl_Position = uMvpMatrix * vertexPosition;" +
- "}";
-
- var fragment = "" +
- "varying lowp vec4 vColor;" +
- "uniform lowp vec4 uColor;" +
- "" +
- "void main()" +
- "{" +
- " gl_FragColor = vColor * uColor;" +
- "}";
-
- var shader = new dali.Shader(vertex, fragment, dali.ShaderHints.HINT_NONE);
- assert.ok(shader);
-
- var material = new dali.Material(shader);
- assert.ok(material);
-
- var renderer = new dali.Renderer(geometry, material);
- assert.ok(renderer);
-
- var actor = new dali.Actor();
- assert.ok(actor);
-
- actor.addRenderer(renderer);
-
- dali.stage.add(actor);
-
- actor.parentOrigin = [0.5, 0.5, 0.0];
- actor.size = [100,100,1];
-}
-
-
-QUnit.test( "Exercise view helpers", function( assert ) {
-
- // just setting the back colour doesnt trigger a redraw in Dali so we
- // add a quad just to see the test running
- addOnScreenQuad(assert);
-
- var done1 = assert.async();
- var done2 = assert.async();
- var done3 = assert.async();
-
- var w = dali.canvas.width;
- var h = dali.canvas.height;
- var col = dali.getClearColor(0);
- console.log(col);
-
- function one() {
- dali.onePane();
- dali.setFrontView(0, 0, 0, w, h);
- dali.setClearColor(0, col);
- done3();
- }
-
- function three() {
- dali.threePane();
- dali.setClearColor(0, [0.4, 0, 0, 1]);
- dali.setClearColor(1, [0, 0.4, 0, 1]);
- dali.setClearColor(2, [0, 0, 0.4, 1]);
- dali.setFrontView(0, 0, 0, w / 2 - 5, h);
- dali.setTopView(1, w / 2, 0, w / 2, h / 2 - 5);
- dali.setRightView(2, w / 2, h / 2 + 5, w / 2, h / 2 - 5);
-
- window.setTimeout(one, 100);
- done2();
- }
-
- function two() {
- dali.twoPane();
- dali.setFrontView(0, 0, 0, w / 2 - 10, h);
- dali.setTopView(1, 210, 0, w / 2 - 10, h);
- dali.setClearColor(0, [0.4, 0, 0, 1]);
- dali.setClearColor(1, [0, 0.4, 0, 1]);
-
- window.setTimeout(three, 100);
- done1();
- }
-
- //one();
-
- window.setTimeout(two, 100);
-
-});
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "type-info-wrapper.h"
-
-// EXTERNAL INCLUDES
-
-// INTERNAL INCLUDES
-#include "property-value-wrapper.h"
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-std::vector<std::string> GetAllProperties(Dali::TypeInfo self)
-{
- std::vector<std::string> names;
-
- // get the other properties
- if(Dali::Handle handle = Dali::Handle::DownCast( self.CreateInstance() ) )
- {
- typedef Dali::Property::IndexContainer IndexContainer;
-
- Dali::Property::IndexContainer indices;
- handle.GetPropertyIndices( indices );
-
- for(IndexContainer::Iterator iter(indices.Begin()); iter != indices.End(); ++iter)
- {
- std::string name = handle.GetPropertyName( *iter );
-
- names.push_back(name);
- }
- }
- else
- {
- // all we can do is get the event side properties
- // get the event side properties
- Property::IndexContainer indices;
- self.GetPropertyIndices( indices );
- for(Property::IndexContainer::Iterator iter(indices.Begin()); iter != indices.End(); ++iter)
- {
- std::string name = self.GetPropertyName( *iter );
- names.push_back(name);
- }
- }
-
- return names;
-}
-
-std::vector<int> GetPropertyIndices(Dali::TypeInfo& self)
-{
- Dali::Property::IndexContainer indices;
- self.GetPropertyIndices( indices );
-
- std::vector<int> ret( indices.Begin(), indices.End() );
- return ret;
-}
-
-std::vector<std::string> GetActions(Dali::TypeInfo& self)
-{
- std::vector<std::string> names;
- std::size_t size = self.GetActionCount();
- for(std::size_t i = 0; i < size; i++)
- {
- names.push_back(self.GetActionName(i));
- }
- return names;
-}
-
-std::vector<std::string> GetSignals(Dali::TypeInfo& self)
-{
- std::vector<std::string> names;
- std::size_t size = self.GetSignalCount();
- for(std::size_t i = 0; i < size; i++)
- {
- names.push_back(self.GetSignalName(i));
- }
- return names;
-}
-
-std::vector<std::string> GetBases(Dali::TypeInfo& self)
-{
- std::vector<std::string> names;
-
- Dali::TypeRegistry registry = Dali::TypeRegistry::Get();
-
- Dali::TypeInfo base = registry.GetTypeInfo( self.GetBaseName() );
-
- while(base)
- {
- base = registry.GetTypeInfo( base.GetBaseName() );
- names.push_back(base.GetName());
- }
-
- return names;
-}
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
+++ /dev/null
-#ifndef __DALI_TYPE_INFO_WRAPPER_H__
-#define __DALI_TYPE_INFO_WRAPPER_H__
-
-/*
- * Copyright (c) 2015 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/dali-core.h>
-
-#include "emscripten/emscripten.h"
-#include "emscripten/bind.h"
-#include <vector>
-#include <string>
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Gets all properties from TypeInfo
- *
- * @param[in] self The TypeInfo
- *
- * @returns A list of property names
- *
- */
-std::vector<std::string> GetAllProperties(Dali::TypeInfo self);
-
-/**
- * Gets all property indices from TypeInfo
- *
- * @param[in] self The TypeInfo
- *
- * @returns A list of property indices
- *
- */
-std::vector<int> GetPropertyIndices(Dali::TypeInfo& self);
-
-/**
- * Gets all actions from TypeInfo
- *
- * @param[in] self The TypeInfo
- *
- * @returns A list of property action names
- *
- */
-std::vector<std::string> GetActions(Dali::TypeInfo& self);
-
-/**
- * Gets all signals from TypeInfo
- *
- * @param[in] self The TypeInfo
- *
- * @returns A list of signal names
- *
- */
-std::vector<std::string> GetSignals(Dali::TypeInfo& self);
-
-/**
- * Gets all bases classes from TypeInfo
- *
- * @param[in] self The TypeInfo
- *
- * @returns A list of base class names
- *
- */
-std::vector<std::string> GetBases(Dali::TypeInfo& self);
-
-/**
- * Check if a TypeInfo has a base name
- *
- * @param[in] self The TypeInfo
- * @param[in] baseName The base class name
- *
- * @returns true if baseName is a base class of self
- *
- */
-bool InheritsFrom(Dali::TypeInfo& self, const std::string& baseName);
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
#define __DALI_INTEGRATION_ADAPTOR_H__
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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/public-api/math/rect.h>
#include <dali/public-api/events/touch-event.h>
#include <dali/public-api/common/view-mode.h>
+#include <dali/public-api/math/uint-16-pair.h>
// INTERNAL INCLUDES
-
#ifdef DALI_ADAPTOR_COMPILATION // full path doesn't exist until adaptor is installed so we have to use relative
// @todo Make dali-adaptor code folder structure mirror the folder structure installed to dali-env
#include <window.h>
typedef Signal< void (Adaptor&) > AdaptorSignalType; ///< Generic Type for adaptor signals
+ typedef Uint16Pair SurfaceSize; ///< Surface size type
+
public:
/**
* @brief Create a new adaptor using the window.
/**
* @brief Informs core the surface size has changed
*/
- void SurfaceSizeChanged( const PositionSize& positionSize );
+ void SurfaceSizeChanged( SurfaceSize surfaceSize );
public: // Signals
Application Application::New( int* argc, char **argv[] )
{
- Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, "", OPAQUE,
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, "", OPAQUE, PositionSize(),
Internal::Adaptor::Framework::NORMAL);
return Application(internal.Get());
}
Application Application::New( int* argc, char **argv[], const std::string& stylesheet )
{
- Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, OPAQUE,
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, OPAQUE, PositionSize(),
Internal::Adaptor::Framework::NORMAL);
return Application(internal.Get());
}
Application Application::New( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode )
{
- Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode,
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, PositionSize(),
Internal::Adaptor::Framework::NORMAL);
return Application(internal.Get());
}
const unsigned int ADAPTOR_MAJOR_VERSION = 1;
const unsigned int ADAPTOR_MINOR_VERSION = 2;
-const unsigned int ADAPTOR_MICRO_VERSION = 44;
+const unsigned int ADAPTOR_MICRO_VERSION = 46;
const char * const ADAPTOR_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
// INTERNAL INCLUDES
#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/dali-vector.h>
#include "key.h"
namespace Dali
*/
DALI_IMPORT_API bool UngrabKey( Window window, Dali::KEY daliKey );
+
+/**
+ * @PLATFORM
+ * @brief Grabs the list of keys specified by @Dali::Vector of keys for @a window in @Vector of grabModes.
+ *
+ * @details This function can be used for following example scenarios:
+ * - TV - A user might want to change the volume or channel of the background TV contents while focusing on the foregrund app.
+ * - Mobile - When a user presses Home key, the homescreen appears regardless of current foreground app.
+ * - Mobile - Using volume up/down as zoom up/down in camera apps.
+ *
+ * @SINCE_1_2.0
+ * @PRIVLEVEL_PLATFORM
+ * @PRIVILEGE_KEYGRAB
+ * @param[in] window The window to set
+ * @param[in] daliKeyVector The Dali::Vector of key codes to grab (defined in key.h)
+ * @param[in] grabModeVector The Dali::Vector of grab modes for the keys
+ * @param[in] returnVector The Dali::Vector of return boolean values for the results of multiple grab succeeds/fails
+ * @return bool false when error occurs
+ */
+DALI_IMPORT_API bool GrabKeyList( Window window, const Dali::Vector<Dali::KEY>& daliKeyVector, const Dali::Vector<KeyGrabMode>& grabModeVector, Dali::Vector<bool>& returnVector);
+
+
+/**
+ * @PLATFORM
+ * @brief Ungrabs the list of keys specified by @Dali::Vector of keys for @a window.
+ *
+ * @SINCE_1_2.0
+ * @PRIVLEVEL_PLATFORM
+ * @PRIVILEGE_KEYGRAB
+ * @param[in] window The window to set
+ * @param[in] daliKeyVector The Dali::Vector of key codes to ungrab (defined in key.h)
+ * @param[in] returnVector The Dali::Vector of return boolean values for the results of multiple ungrab succeeds/fails
+ * @return bool false when error occurs
+ * @note If this function is called between key down and up events of a grabbed key,
+ * an application doesn't receive the key up event.
+ */
+DALI_IMPORT_API bool UngrabKeyList( Window window, const Dali::Vector<Dali::KEY>& daliKeyVector, Dali::Vector<bool>& returnVector);
+
+
} // namespace KeyGrab
/**
// place holder
};
-Window* Window::New(const PositionSize& posSize, const std::string& name, const std::string& className, bool isTransparent)
+Window* Window::New( const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent )
{
Window* window = new Window();
window->mIsTransparent = isTransparent;
- window->Initialize(posSize, name, className);
+ window->Initialize( positionSize, name, className );
return window;
}
mIsFocusAcceptable( true ),
mVisible( true ),
mOpaqueState( false ),
+ mResizeEnabled( true ),
mIndicator( NULL ),
mIndicatorOrientation( Dali::Window::PORTRAIT ),
mNextIndicatorOrientation( Dali::Window::PORTRAIT ),
delete mSurface;
}
-void Window::Initialize(const PositionSize& windowPosition, const std::string& name, const std::string& className)
+void Window::Initialize(const PositionSize& positionSize, const std::string& name, const std::string& className)
{
// create an Wayland window by default
Any surface;
- Wayland::RenderSurface* windowSurface = new Wayland::RenderSurface( windowPosition, surface, name, mIsTransparent );
+ Wayland::RenderSurface* windowSurface = new Wayland::RenderSurface( positionSize, surface, name, mIsTransparent );
mSurface = windowSurface;
mOrientation = Orientation::New(this);
-
}
void Window::DoShowIndicator( Dali::Window::WindowOrientation lastOrientation )
return 0;
}
+void Window::SetSize( Dali::DevelWindow::WindowSize size )
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ if( positionSize.width != size.GetWidth() || positionSize.height != size.GetHeight() )
+ {
+ positionSize.width = size.GetWidth();
+ positionSize.height = size.GetHeight();
+
+ mSurface->MoveResize( positionSize );
+
+ mAdaptor->SurfaceSizeChanged( Dali::Adaptor::SurfaceSize( positionSize.width, positionSize.height ) );
+
+ // Emit signal
+ mResizedSignal.Emit( Dali::DevelWindow::WindowSize( positionSize.width, positionSize.height ) );
+ }
+}
+
+Dali::DevelWindow::WindowSize Window::GetSize()
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ return Dali::DevelWindow::WindowSize( positionSize.width, positionSize.height );
+}
+
+void Window::SetPosition( Dali::DevelWindow::WindowPosition position )
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ if( positionSize.x != position.GetX() || positionSize.y != position.GetY() )
+ {
+ positionSize.x = position.GetX();
+ positionSize.y = position.GetY();
+
+ mSurface->MoveResize( positionSize );
+ }
+}
+
+Dali::DevelWindow::WindowPosition Window::GetPosition()
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ return Dali::DevelWindow::WindowPosition( positionSize.x, positionSize.y );
+}
+
} // Adaptor
} // Internal
} // Dali
}
WatchApplication::WatchApplication( int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode )
-: Application(argc, argv, stylesheet, windowMode, Framework::WATCH)
+: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::WATCH)
{
}
};
-Window* Window::New(const PositionSize& posSize, const std::string& name, const std::string& className, bool isTransparent)
+Window* Window::New( const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent )
{
Window* window = new Window();
window->mIsTransparent = isTransparent;
- window->Initialize(posSize, name, className);
+ window->Initialize( positionSize, name, className );
return window;
}
mIsFocusAcceptable( true ),
mVisible( true ),
mOpaqueState( false ),
+ mResizeEnabled( true ),
mIndicator( NULL ),
mIndicatorOrientation( Dali::Window::PORTRAIT ),
mNextIndicatorOrientation( Dali::Window::PORTRAIT ),
delete mSurface;
}
-void Window::Initialize(const PositionSize& windowPosition, const std::string& name, const std::string& className)
+void Window::Initialize(const PositionSize& positionSize, const std::string& name, const std::string& className)
{
// create an X11 window by default
Any surface;
- ECore::WindowRenderSurface* windowSurface = new ECore::WindowRenderSurface( windowPosition, surface, name, className, mIsTransparent );
+ ECore::WindowRenderSurface* windowSurface = new ECore::WindowRenderSurface( positionSize, surface, name, className, mIsTransparent );
windowSurface->Map();
mSurface = windowSurface;
return 0;
}
+void Window::SetSize( Dali::DevelWindow::WindowSize size )
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ if( positionSize.width != size.GetWidth() || positionSize.height != size.GetHeight() )
+ {
+ positionSize.width = size.GetWidth();
+ positionSize.height = size.GetHeight();
+
+ mSurface->MoveResize( positionSize );
+
+ mAdaptor->SurfaceSizeChanged( Dali::Adaptor::SurfaceSize( positionSize.width, positionSize.height ) );
+
+ // Emit signal
+ mResizedSignal.Emit( Dali::DevelWindow::WindowSize( positionSize.width, positionSize.height ) );
+ }
+}
+
+Dali::DevelWindow::WindowSize Window::GetSize()
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ return Dali::DevelWindow::WindowSize( positionSize.width, positionSize.height );
+}
+
+void Window::SetPosition( Dali::DevelWindow::WindowPosition position )
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ if( positionSize.x != position.GetX() || positionSize.y != position.GetY() )
+ {
+ positionSize.x = position.GetX();
+ positionSize.y = position.GetY();
+
+ mSurface->MoveResize( positionSize );
+ }
+}
+
+Dali::DevelWindow::WindowPosition Window::GetPosition()
+{
+ PositionSize positionSize = mSurface->GetPositionSize();
+
+ return Dali::DevelWindow::WindowPosition( positionSize.x, positionSize.y );
+}
+
} // Adaptor
} // Internal
# Clean up old coverage data
if [ -d ../build/tizen ] ; then
- rm -f ../build/tizen/dali-toolkit/.libs/*.gcda
+ rm -f ../build/tizen/dali/.libs/*.gcda
fi
find build \( -name "*.gcda" \) -exec rm '{}' \;
ret=$?
if [ $ret -ne 6 ] ; then
if [ $opt_debug -ne 0 ] ; then
- if [ $ret -eq 0 ] ; then
- gdb --args build/src/$mod/tct-$mod-core $1
- fi
+ echo DEBUGGING:
+ gdb --args build/src/$mod/tct-$mod-core $1
+
else
echo $output
if [ $ret -eq 0 ] ; then echo -e "\nPassed" ; fi
utc-Dali-GifLoader.cpp
utc-Dali-IcoLoader.cpp
utc-Dali-ImageOperations.cpp
+ utc-Dali-Internal-PixelBuffer.cpp
utc-Dali-Lifecycle-Controller.cpp
utc-Dali-TiltSensor.cpp
)
--- /dev/null
+/*
+ * Copyright (c) 2014 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/public-api/dali-core.h>
+
+#include <dali-test-suite-utils.h>
+
+// Internal headers are allowed here
+
+#include <platform-abstractions/portable/pixel-manipulation.h>
+
+using namespace Dali;
+using namespace Dali::Internal::Adaptor;
+void utc_dali_internal_pixel_data_startup()
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_internal_pixel_data_cleanup()
+{
+ test_return_value = TET_PASS;
+}
+
+const char* ChannelToString( Dali::Internal::Adaptor::Channel channel )
+{
+ switch(channel)
+ {
+ case LUMINANCE: return "Luminance";
+ case RED: return "Red";
+ case GREEN: return "Green";
+ case BLUE: return "Blue";
+ case ALPHA: return "Alpha";
+ default:
+ return "Unknown";
+ }
+}
+
+const char* FormatToString( Dali::Pixel::Format format )
+{
+ switch(format)
+ {
+ case Dali::Pixel::A8: return "A8";
+ case Dali::Pixel::L8: return "L8";
+ case Dali::Pixel::LA88: return "LA88";
+ case Dali::Pixel::RGB565: return "RGB565";
+ case Dali::Pixel::BGR565: return "BGR565";
+ case Dali::Pixel::RGBA4444: return "RGBA4444";
+ case Dali::Pixel::BGRA4444: return "BGRA4444";
+ case Dali::Pixel::RGBA5551: return "RGBA5551";
+ case Dali::Pixel::BGRA5551: return "BGRA5551";
+
+ case Dali::Pixel::RGB888: return "RGB888";
+ case Dali::Pixel::RGBA8888: return "RGBA8888";
+ case Dali::Pixel::BGRA8888: return "BGRA8888";
+
+ default:
+ return "Unknown";
+ }
+}
+
+
+int UtcDaliPixelManipulation01(void)
+{
+ tet_infoline("Testing Dali::Internal::AdaptorManipulation HasChannel");
+
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::A8, Dali::Internal::Adaptor::ALPHA ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::A8, Dali::Internal::Adaptor::LUMINANCE ), false, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::L8, Dali::Internal::Adaptor::LUMINANCE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::L8, Dali::Internal::Adaptor::ALPHA ), false, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::LA88, Dali::Internal::Adaptor::LUMINANCE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::LA88, Dali::Internal::Adaptor::ALPHA ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::LA88, Dali::Internal::Adaptor::RED ), false, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Adaptor::RED ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Adaptor::GREEN ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Adaptor::BLUE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Adaptor::LUMINANCE ), false, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Adaptor::RED ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Adaptor::GREEN ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Adaptor::BLUE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Adaptor::ALPHA ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Adaptor::LUMINANCE ), false, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( Dali::Internal::Adaptor::HasChannel( Dali::Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR, Dali::Internal::Adaptor::BLUE ), false, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+
+int UtcDaliPixelManipulation02(void)
+{
+ tet_infoline("Testing Dali::Internal::AdaptorManipulation Read/WriteChannel");
+
+ unsigned char pixel[4] = {0,0,0,0};
+
+ for( int formatIdx=1; formatIdx<Dali::Pixel::COMPRESSED_R11_EAC; ++formatIdx)
+ {
+ pixel[0] = 0xFF;
+ pixel[1] = 0xFF;
+ pixel[2] = 0xFF;
+ pixel[3] = 0xFF;
+
+ for( int channelIdx=0; channelIdx < Dali::Internal::Adaptor::MAX_NUMBER_OF_CHANNELS; ++channelIdx )
+ {
+ Dali::Pixel::Format format = static_cast<Dali::Pixel::Format>(formatIdx);
+ Dali::Internal::Adaptor::Channel channel = static_cast<Dali::Internal::Adaptor::Channel>(channelIdx);
+ if( Dali::Internal::Adaptor::HasChannel( format, channel ) )
+ {
+ Dali::Internal::Adaptor::WriteChannel( &pixel[0], format, channel, 0x15);
+ unsigned int value = Dali::Internal::Adaptor::ReadChannel( &pixel[0], format, channel );
+
+ tet_printf( "Testing writing and reading to %s channel in %s format:\n",
+ ChannelToString(channel), FormatToString(format) );
+
+ if( channel == Dali::Internal::Adaptor::ALPHA && (format == Dali::Pixel::RGBA5551 || format == Dali::Pixel::BGRA5551 ) )
+ {
+ DALI_TEST_EQUALS( value, 0x1, TEST_LOCATION );
+ }
+ else if( format == Dali::Pixel::RGBA4444 || format == Dali::Pixel::BGRA4444 )
+ {
+ DALI_TEST_EQUALS( value, 0x05, TEST_LOCATION );
+ }
+ else
+ {
+ DALI_TEST_EQUALS( value, 0x15, TEST_LOCATION );
+ }
+ }
+ }
+ }
+
+ END_TEST;
+}
+
+
+int UtcDaliPixelManipulation03N(void)
+{
+ tet_infoline("Testing Dali::Internal::AdaptorManipulation Read/WriteChannel");
+
+ unsigned char pixel[4] = {0,0,0,0};
+
+ for( int formatIdx=1; formatIdx<Dali::Pixel::COMPRESSED_R11_EAC; ++formatIdx)
+ {
+ pixel[0] = 0xFF;
+ pixel[1] = 0xFF;
+ pixel[2] = 0xFF;
+ pixel[3] = 0xFF;
+
+ for( int channelIdx=0; channelIdx < Dali::Internal::Adaptor::MAX_NUMBER_OF_CHANNELS; ++channelIdx )
+ {
+ Dali::Pixel::Format format = static_cast<Dali::Pixel::Format>(formatIdx);
+ Dali::Internal::Adaptor::Channel channel = static_cast<Dali::Internal::Adaptor::Channel>(channelIdx);
+ if( ! Dali::Internal::Adaptor::HasChannel( format, channel ) )
+ {
+ unsigned int value = Dali::Internal::Adaptor::ReadChannel( &pixel[0], format, channel );
+
+ tet_printf( "Testing reading from %s channel in %s format:\n",
+ ChannelToString(channel), FormatToString(format) );
+
+ DALI_TEST_EQUALS( value, 0x00, TEST_LOCATION );
+ }
+ }
+ }
+
+ END_TEST;
+}
SET(CAPI_LIB "dali-adaptor")
SET(TC_SOURCES
utc-Dali-Application.cpp
- utc-Dali-BitmapLoader.cpp
utc-Dali-FileLoader.cpp
utc-Dali-GifLoading.cpp
utc-Dali-ImageLoading.cpp
utc-Dali-Key.cpp
utc-Dali-NativeImageSource.cpp
+ utc-Dali-PixelBuffer.cpp
utc-Dali-SingletonService.cpp
utc-Dali-Timer.cpp
utc-Dali-TtsPlayer.cpp
+++ /dev/null
-/*
- * Copyright (c) 2015 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 <stdlib.h>
-#include <dali/dali.h>
-#include <dali-test-suite-utils.h>
-#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
-
-using namespace Dali;
-
-namespace
-{
-// resolution: 34*34, pixel format: RGBA8888
-static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
-// resolution: 128*128, pixel format: RGB888
-static const char* gImage_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
-
-// this is image is not exist, for negative test
-static const char* gImageNonExist = "non-exist.jpg";
-}
-
-void utc_dali_bitmap_loader_startup(void)
-{
- test_return_value = TET_UNDEF;
-}
-
-void utc_dali_bitmap_loader_cleanup(void)
-{
- test_return_value = TET_PASS;
-}
-
-int UtcDaliBitmapLoaderNew(void)
-{
- TestApplication application;
-
- // invoke default handle constructor
- BitmapLoader loader;
-
- DALI_TEST_CHECK( !loader );
-
- // initialise handle
- loader = BitmapLoader::New( gImage_34_RGBA );
-
- DALI_TEST_CHECK( loader );
- END_TEST;
-}
-
-int UtcDaliBitmapLoaderCopyConstructor(void)
-{
- TestApplication application;
-
- BitmapLoader loader = BitmapLoader::New( gImage_34_RGBA);
- BitmapLoader loaderCopy(loader);
-
- DALI_TEST_EQUALS( (bool)loaderCopy, true, TEST_LOCATION );
- END_TEST;
-}
-
-int UtcDaliBitmapLoaderAssignmentOperator(void)
-{
- TestApplication application;
-
- BitmapLoader loader = BitmapLoader::New( gImage_34_RGBA );
-
- BitmapLoader loader2;
- DALI_TEST_EQUALS( (bool)loader2, false, TEST_LOCATION );
-
- loader2 = loader;
- DALI_TEST_EQUALS( (bool)loader2, true, TEST_LOCATION );
-
- END_TEST;
-}
-
-int UtcDaliBitmapLoaderGetUrl(void)
-{
- TestApplication application;
-
- BitmapLoader loader = BitmapLoader::New( gImage_34_RGBA );
- DALI_TEST_CHECK( loader.GetUrl() == gImage_34_RGBA );
-
- END_TEST;
-}
-
-
-int UtcDaliBitmapLoaderLoadP(void)
-{
- TestApplication application;
-
- BitmapLoader loader1 = BitmapLoader::New( gImage_34_RGBA );
- DALI_TEST_CHECK( ! loader1.IsLoaded() );
- loader1.Load();
- DALI_TEST_CHECK( loader1.IsLoaded() );
- PixelData pixelData1 = loader1.GetPixelData();
- DALI_TEST_CHECK( pixelData1 );
- DALI_TEST_CHECK( pixelData1.GetWidth() == 34u );
- DALI_TEST_CHECK( pixelData1.GetHeight() == 34u );
- DALI_TEST_CHECK( pixelData1.GetPixelFormat() == Pixel::RGBA8888 );
-
- BitmapLoader loader2 = BitmapLoader::New( gImage_128_RGB );
- DALI_TEST_CHECK( ! loader2.IsLoaded() );
- loader2.Load();
- DALI_TEST_CHECK( loader2.IsLoaded() );
- PixelData pixelData2 = loader2.GetPixelData();
- DALI_TEST_CHECK( pixelData2 );
- DALI_TEST_CHECK( pixelData2.GetWidth() == 128u );
- DALI_TEST_CHECK( pixelData2.GetHeight() == 128u );
- DALI_TEST_CHECK( pixelData2.GetPixelFormat() == Pixel::RGB888 );
-
- END_TEST;
-}
-
-int UtcDaliBitmapLoaderLoadN(void)
-{
- TestApplication application;
-
- BitmapLoader loader = BitmapLoader::New( gImageNonExist );
- DALI_TEST_CHECK( ! loader.IsLoaded() );
- loader.Load();
-
- // cannot load image that is not exist
- DALI_TEST_CHECK( ! loader.IsLoaded() );
- PixelData pixelData = loader.GetPixelData();
- DALI_TEST_CHECK( !pixelData);
-
- END_TEST;
-}
int UtcDaliLoadImageP(void)
{
- PixelData pixelData = Dali::LoadImageFromFile( gImage_34_RGBA );
- DALI_TEST_CHECK( pixelData );
- DALI_TEST_EQUALS( pixelData.GetWidth(), 34u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData.GetHeight(), 34u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
-
- PixelData pixelData2 = Dali::LoadImageFromFile( gImage_128_RGB );
- DALI_TEST_CHECK( pixelData2 );
- DALI_TEST_EQUALS( pixelData2.GetWidth(), 128u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData2.GetHeight(), 128u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData2.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION );
+ Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile( gImage_34_RGBA );
+ DALI_TEST_CHECK( pixelBuffer );
+ DALI_TEST_EQUALS( pixelBuffer.GetWidth(), 34u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer.GetHeight(), 34u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+ Devel::PixelBuffer pixelBuffer2 = Dali::LoadImageFromFile( gImage_128_RGB );
+ DALI_TEST_CHECK( pixelBuffer2 );
+ DALI_TEST_EQUALS( pixelBuffer2.GetWidth(), 128u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer2.GetHeight(), 128u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer2.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION );
END_TEST;
}
int UtcDaliLoadImageN(void)
{
- PixelData pixelData = Dali::LoadImageFromFile( gImageNonExist );
- DALI_TEST_CHECK( !pixelData );
+ Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile( gImageNonExist );
+ DALI_TEST_CHECK( !pixelBuffer );
END_TEST;
}
std::string url2("file://");
url2.append( gImage_128_RGB );
- PixelData pixelData = Dali::DownloadImageSynchronously( url );
- DALI_TEST_CHECK( pixelData );
- DALI_TEST_EQUALS( pixelData.GetWidth(), 34u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData.GetHeight(), 34u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+ Devel::PixelBuffer pixelBuffer = Dali::DownloadImageSynchronously( url );
+ DALI_TEST_CHECK( pixelBuffer );
+ DALI_TEST_EQUALS( pixelBuffer.GetWidth(), 34u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer.GetHeight(), 34u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
- PixelData pixelData2 = Dali::DownloadImageSynchronously( url2 );
- DALI_TEST_CHECK( pixelData2 );
- DALI_TEST_EQUALS( pixelData2.GetWidth(), 128u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData2.GetHeight(), 128u, TEST_LOCATION );
- DALI_TEST_EQUALS( pixelData2.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION );
+ Devel::PixelBuffer pixelBuffer2 = Dali::DownloadImageSynchronously( url2 );
+ DALI_TEST_CHECK( pixelBuffer2 );
+ DALI_TEST_EQUALS( pixelBuffer2.GetWidth(), 128u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer2.GetHeight(), 128u, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelBuffer2.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION );
END_TEST;
}
int UtcDaliDownloadImageN(void)
{
- PixelData pixelData = Dali::DownloadImageSynchronously( gImageNonExist );
- DALI_TEST_CHECK( !pixelData );
+ Devel::PixelBuffer pixelBuffer = Dali::DownloadImageSynchronously( gImageNonExist );
+ DALI_TEST_CHECK( !pixelBuffer );
END_TEST;
}
--- /dev/null
+/*
+ * Copyright (c) 2017 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/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include "mesh-builder.h"
+using namespace Dali;
+
+void utc_dali_pixelbuffer_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_pixelbuffer_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+int UtcDaliPixelBufferCreatePixelData(void)
+{
+ TestApplication application;
+
+ unsigned int width = 20u;
+ unsigned int height = 20u;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGB888 );
+
+ PixelData pixelData = imageData.CreatePixelData();
+
+ DALI_TEST_EQUALS( true, (bool)pixelData, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+void Mask1stQuadrant( Devel::PixelBuffer maskData )
+{
+ int width = maskData.GetWidth();
+ int height = maskData.GetHeight();
+ Pixel::Format pixelFormat = maskData.GetPixelFormat();
+ int bpp = Pixel::GetBytesPerPixel(pixelFormat);
+
+ unsigned char* maskBuffer = maskData.GetBuffer();
+ memset( maskBuffer, 0, width*height*bpp );
+ int offset=0;
+ for( int x=0; x<width; ++x)
+ {
+ for( int y=0; y<height; ++y)
+ {
+ if(x>=width/2 || y>=height/2)
+ {
+ for(int b=0;b<bpp;++b)
+ {
+ maskBuffer[offset+b] = 0xff;
+ }
+ }
+ offset+=bpp;
+ }
+ }
+}
+
+void FillCheckerboard( Devel::PixelBuffer imageData )
+{
+ int width = imageData.GetWidth();
+ int height = imageData.GetHeight();
+ Pixel::Format pixelFormat = imageData.GetPixelFormat();
+ int bpp = Pixel::GetBytesPerPixel(pixelFormat);
+
+ unsigned char* imageBuffer = imageData.GetBuffer();
+ memset( imageBuffer, 0, width*height*bpp );
+ int offset=0;
+ for( int x=0; x<width; ++x)
+ {
+ for( int y=0; y<height; ++y)
+ {
+ // on even lines, odd pixels, or on odd lines, even pixels
+ if( (x%2 && y%2==0) || (x%2==0 && y%2) )
+ {
+ switch(pixelFormat)
+ {
+ case Pixel::RGBA5551:
+ imageBuffer[offset] = 0xFF;
+ imageBuffer[offset+1] = 0xFF;
+ break;
+ case Pixel::RGBA4444:
+ imageBuffer[offset] = 0xFF;
+ imageBuffer[offset+1] = 0xFF;
+ break;
+ case Pixel::RGB565:
+ imageBuffer[offset] = 0xFF;
+ imageBuffer[offset+1] = 0xFF;
+ break;
+ case Pixel::RGB888:
+ imageBuffer[offset] = 0xFF;
+ imageBuffer[offset+1] = 0xFF;
+ imageBuffer[offset+2] = 0xFF;
+ break;
+ case Pixel::RGBA8888:
+ imageBuffer[offset] = 0xFF;
+ imageBuffer[offset+1] = 0xFF;
+ imageBuffer[offset+2] = 0xFF;
+ imageBuffer[offset+3] = 0xFF;
+ break;
+ default:
+ break;
+ }
+ }
+ offset+=bpp;
+ }
+ }
+}
+
+int UtcDaliPixelBufferNew01P(void)
+{
+ TestApplication application;
+ Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::RGBA8888 );
+ DALI_TEST_CHECK( pixbuf );
+ DALI_TEST_CHECK( pixbuf.GetBuffer() != NULL );
+ END_TEST;
+}
+
+int UtcDaliPixelBufferNew01N(void)
+{
+ TestApplication application;
+ Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 0, 0, Pixel::RGBA8888 );
+ DALI_TEST_CHECK( pixbuf );
+ DALI_TEST_CHECK( pixbuf.GetBuffer() == NULL );
+ END_TEST;
+}
+
+int UtcDaliPixelBufferConvert(void)
+{
+ TestApplication application;
+ TestGlAbstraction& gl=application.GetGlAbstraction();
+ TraceCallStack& textureTrace=gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::RGB565 );
+ FillCheckerboard(pixbuf);
+
+ {
+ Devel::PixelBuffer pixbufPrime = pixbuf; // store a second handle to the data
+
+ Dali::PixelData pixelData = Devel::PixelBuffer::Convert( pixbuf );
+ DALI_TEST_CHECK( !pixbuf );
+
+ // check the buffer in the second handle is empty
+ DALI_TEST_CHECK( pixbufPrime.GetBuffer() == NULL );
+
+ DALI_TEST_CHECK( pixelData );
+ DALI_TEST_EQUALS( pixelData.GetWidth(), 10, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelData.GetHeight(), 10, TEST_LOCATION );
+ DALI_TEST_EQUALS( pixelData.GetPixelFormat(), Pixel::RGB565, TEST_LOCATION );
+
+ // Try drawing it
+ Texture t = Texture::New(TextureType::TEXTURE_2D, Pixel::RGB565, 10, 10);
+ t.Upload( pixelData );
+ TextureSet ts = TextureSet::New();
+ ts.SetTexture(0, t);
+ Geometry g = CreateQuadGeometry();
+ Shader s = Shader::New("v", "f");
+ Renderer r = Renderer::New( g, s );
+ r.SetTextures(ts);
+ Actor a = Actor::New();
+ a.AddRenderer(r);
+ a.SetSize(10, 10);
+ a.SetParentOrigin(ParentOrigin::CENTER);
+ Stage::GetCurrent().Add(a);
+
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ // Let secondary scope destroy pixbufPrime
+ }
+
+ END_TEST;
+}
+
+int UtcDaliPixelBufferGetWidth(void)
+{
+ TestApplication application;
+ Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::RGB565 );
+ FillCheckerboard(pixbuf);
+
+ DALI_TEST_EQUALS( pixbuf.GetWidth(), 10, TEST_LOCATION ) ;
+
+ END_TEST;
+}
+
+int UtcDaliPixelBufferGetHeight(void)
+{
+ TestApplication application;
+ Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::RGB565 );
+ FillCheckerboard(pixbuf);
+
+ DALI_TEST_EQUALS( pixbuf.GetHeight(), 10, TEST_LOCATION ) ;
+
+ END_TEST;
+}
+
+int UtcDaliPixelBufferGetPixelFormat(void)
+{
+ TestApplication application;
+ Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::RGB565 );
+ FillCheckerboard(pixbuf);
+
+ DALI_TEST_EQUALS( pixbuf.GetPixelFormat(), Pixel::RGB565, TEST_LOCATION ) ;
+
+ END_TEST;
+}
+
+
+
+int UtcDaliPixelBufferMask01(void)
+{
+ TestApplication application;
+
+ unsigned int width = 10u;
+ unsigned int height = 10u;
+ Pixel::Format pixelFormat = Pixel::L8;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, pixelFormat );
+
+ Mask1stQuadrant(maskData);
+
+ width = 20u;
+ height = 20u;
+ pixelFormat = Pixel::RGBA5551;
+
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, pixelFormat );
+ FillCheckerboard(imageData);
+
+ imageData.ApplyMask( maskData );
+
+ // Test that the pixel format has been promoted to RGBA8888
+ DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+ // Test that a pixel in the first quadrant has no alpha value
+ unsigned char* buffer = imageData.GetBuffer();
+ DALI_TEST_EQUALS( buffer[3], 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
+
+ // Test that an even pixel in the second quadrant has a full alpha value
+ DALI_TEST_EQUALS( buffer[43], 0x00u, TEST_LOCATION );
+
+ // Test that an odd pixel in the second quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[47], 0xffu, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliPixelBufferMask02(void)
+{
+ TestApplication application;
+
+ unsigned int width = 10u;
+ unsigned int height = 10u;
+ Pixel::Format pixelFormat = Pixel::L8;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, pixelFormat );
+
+ Mask1stQuadrant(maskData);
+
+ width = 20u;
+ height = 20u;
+ pixelFormat = Pixel::RGBA4444;
+
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, pixelFormat );
+ FillCheckerboard(imageData);
+
+ imageData.ApplyMask( maskData );
+
+ // Test that the pixel format has been promoted to RGBA8888
+ DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+ // Test that a pixel in the first quadrant has no alpha value
+ unsigned char* buffer = imageData.GetBuffer();
+ DALI_TEST_EQUALS( buffer[3], 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
+
+ // Test that an even pixel in the second quadrant has no alpha value
+ DALI_TEST_EQUALS( buffer[43], 0x00u, TEST_LOCATION );
+
+ // Test that an odd pixel in the second quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[47], 0xffu, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliPixelBufferMask03(void)
+{
+ TestApplication application;
+ tet_infoline("Test application of alpha mask to smaller RGB565 image");
+
+ unsigned int width = 20u;
+ unsigned int height = 20u;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::L8 );
+ Mask1stQuadrant(maskData);
+
+ width = 10u;
+ height = 10u;
+ Pixel::Format format = Pixel::RGB565;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, format );
+ FillCheckerboard(imageData);
+
+ imageData.ApplyMask( maskData );
+
+ // Test that the pixel format has been promoted to RGBA8888
+ DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+ // Test that a pixel in the first quadrant has no alpha value
+ unsigned char* buffer = imageData.GetBuffer();
+ DALI_TEST_EQUALS( buffer[3], 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
+
+ // Test that an odd pixel in the second quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[23], 0xffu, TEST_LOCATION );
+
+ // Test that an even pixel in the second quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[27], 0xffu, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliPixelBufferMask04(void)
+{
+ TestApplication application;
+ tet_infoline("Test application of alpha mask to larger RGBA8888 image");
+
+ unsigned int width = 10u;
+ unsigned int height = 10u;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::L8 );
+ Mask1stQuadrant(maskData);
+
+ width = 20u;
+ height = 20u;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ FillCheckerboard(imageData);
+
+ imageData.ApplyMask( maskData );
+
+ // Test that the pixel format has been promoted to RGBA8888
+ DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+ // Test that a pixel in the first quadrant has no alpha value
+ unsigned char* buffer = imageData.GetBuffer();
+ DALI_TEST_EQUALS( buffer[3], 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
+
+ // Test that an even pixel in the second quadrant has no alpha value
+ DALI_TEST_EQUALS( buffer[43], 0x00u, TEST_LOCATION );
+
+ // Test that an odd pixel in the second quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[47], 0xffu, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliPixelBufferMask05(void)
+{
+ TestApplication application;
+ tet_infoline("Test application of alpha mask to smaller RGBA8888 image");
+
+ unsigned int width = 20u;
+ unsigned int height = 20u;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::L8 );
+ Mask1stQuadrant(maskData);
+
+ width = 10u;
+ height = 10u;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ FillCheckerboard(imageData);
+
+ imageData.ApplyMask( maskData );
+
+ // Test that the pixel format has been promoted to RGBA8888
+ DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+ // Test that a pixel in the first quadrant has no alpha value
+ unsigned char* buffer = imageData.GetBuffer();
+ DALI_TEST_EQUALS( buffer[3], 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
+
+ // Test that an odd pixel in the second quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[23], 0xffu, TEST_LOCATION );
+
+ // Test that an even pixel in the second quadrant has no alpha value
+ DALI_TEST_EQUALS( buffer[27], 0x00u, TEST_LOCATION );
+
+ END_TEST;
+}
+++ /dev/null
-cmake_minimum_required(VERSION 2.6)
-
-if( ${EMSCRIPTEN} )
- message("EMSCRIPTEN BUILD")
- set(CMAKE_C_COMPILER "emcc")
- set(CMAKE_CXX_COMPILER "em++")
-else( ${EMSCRIPTEN} )
- message( FATAL_ERROR "Native Build not supported via cmake." )
-endif( ${EMSCRIPTEN} )
-
-if(NOT DEFINED ENV{DESKTOP_PREFIX})
- message( FATAL_ERROR "DESKTOP_PREFIX is required to build adaptor against dali-core. Please make sure you have sourced your setenv script (created by dali_env)." )
-endif()
-
-project(dali-emscripten CXX)
-
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
-
-set(SRCS
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/actor-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/animation-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/dali-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/emscripten-utils.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/handle-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/image-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/property-buffer-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/property-value-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/render-task-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/type-info-wrapper.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/base/separate-update-render/frame-time.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/base/time-service.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/common/gl/egl-image-extensions.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/common/gl/gl-extensions.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/egl-implementation-emscripten.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/main.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/sdl-application.cpp
- ${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/sdl-gl-sync-abstraction.cpp
- ${CMAKE_SOURCE_DIR}/../../platform-abstractions/emscripten/emscripten-callbacks.cpp
- ${CMAKE_SOURCE_DIR}/../../platform-abstractions/emscripten/emscripten-platform-abstraction.cpp
-)
-
-include_directories(${CMAKE_SOURCE_DIR}/../../)
-include_directories(${CMAKE_SOURCE_DIR}/../../adaptors/)
-include_directories(${CMAKE_SOURCE_DIR}/../../adaptors/common)
-include_directories(${CMAKE_SOURCE_DIR}/../../adaptors/tizen)
-include_directories(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten)
-include_directories(${CMAKE_SOURCE_DIR}/../../platform-abstractions/slp)
-
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/all.html all.html COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/dali-page.html dali-page.html COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/dali-tests.css dali-tests.css COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/dali-tests.html dali-tests.html COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/geometry.js geometry.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/properties.js properties.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/signals.js signals.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/math.js math.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/animation.js animation.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/utilities.js utilities.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/shaders.js shaders.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/views.js views.js COPYONLY)
-
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/qunit/qunit-1.21.0.css qunit-1.21.0.css COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/qunit/qunit-1.21.0.js qunit-1.21.0.js COPYONLY)
-
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/dali-wrapper.js dali-wrapper.js COPYONLY)
-
-set(VENDOR "samsung")
-set(PACKAGE ${PROJECT_NAME})
-set(DESKTOP_PREFIX $ENV{DESKTOP_PREFIX})
-set(CPP_DEFINES -DDALI_GLES_VERSION=2)
-
-set(EMSCRIPTEN_ENV_DIR ${DESKTOP_PREFIX}/share/emscripten)
-
-set(DEBUG_FLAGS "-Wall -g -O2")
-set(RELEASE_FLAGS "-Wall -g -O2")
-
-if( ${EMSCRIPTEN} )
- set(DEBUG_FLAGS "${DEBUG_FLAGS} -std=c++11 -DBOOST_ERROR_CODE_HEADER_ONLY")
- set(RELEASE_FLAGS "${RELEASE_FLAGS} -std=c++11 -DBOOST_ERROR_CODE_HEADER_ONLY")
-endif( ${EMSCRIPTEN} )
-
-
-include(FindPkgConfig)
-
-pkg_check_modules(pkgs REQUIRED
- dali-core
- # sdl from emscripten
- )
-
-if( ${EMSCRIPTEN} )
-
-pkg_check_modules(pkgs REQUIRED
- dali-core
- # sdl from emscripten
- )
-
-else( ${EMSCRIPTEN} )
-
-find_library(SDL VERSION "1.2" REQUIRED HINTS $DESKTOP_PREFIX/lib)
-find_library(SDL REQUIRED)
-find_library(SDL_image REQUIRED)
-
-find_library(jpeg REQUIRED)
-find_library(ft2build REQUIRED)
-find_library(turbojpeg REQUIRED)
-
-pkg_check_modules(pkgs REQUIRED
- dali-core
- # sdl from emscripten
- sdl
- egl
- )
-
-include_directories(/usr/local/include/SDL/)
-set(LIBS ${LIBS} -lSDL -lSDL_image -lEGL -lGLESv2)
-
-endif( ${EMSCRIPTEN} )
-
-# non pkg config
-include_directories(${DESKTOP_PREFIX}/include/)
-
-add_definitions( ${CPP_DEFINES} ) # see configure_file() for *.in to *.h style
-
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}")
-
-add_executable(${PROJECT_NAME} ${SRCS})
-
-target_link_libraries(${PROJECT_NAME} ${pkgs_LDFLAGS} ${LIBS}) # "-lm"
-
-# Copy dali-wrapper.js to dali-env
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/dali-wrapper.js ${EMSCRIPTEN_ENV_DIR}/dali-wrapper.js COPYONLY)
-
-# tests
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/all.html ${EMSCRIPTEN_ENV_DIR}/all.html COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/dali-page.html ${EMSCRIPTEN_ENV_DIR}/dali-page.html COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/dali-tests.css ${EMSCRIPTEN_ENV_DIR}/dali-tests.css COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/dali-tests.html ${EMSCRIPTEN_ENV_DIR}/dali-tests.html COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/geometry.js ${EMSCRIPTEN_ENV_DIR}/geometry.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/properties.js ${EMSCRIPTEN_ENV_DIR}/properties.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/signals.js ${EMSCRIPTEN_ENV_DIR}/signals.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/math.js ${EMSCRIPTEN_ENV_DIR}/math.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/animation.js ${EMSCRIPTEN_ENV_DIR}/animation.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/utilities.js ${EMSCRIPTEN_ENV_DIR}/utilities.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/shaders.js ${EMSCRIPTEN_ENV_DIR}/shaders.js COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/views.js ${EMSCRIPTEN_ENV_DIR}/views.js COPYONLY)
-
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/qunit/qunit-1.21.0.css ${EMSCRIPTEN_ENV_DIR}/qunit-1.21.0.css COPYONLY)
-configure_file(${CMAKE_SOURCE_DIR}/../../adaptors/emscripten/wrappers/tests/qunit/qunit-1.21.0.js ${EMSCRIPTEN_ENV_DIR}/qunit-1.21.0.js COPYONLY)
+++ /dev/null
-#!/bin/bash
-
-# This script builds dali-adaptor using Emscripten.
-
-# DESKTOP_PREFIX is required to build Emscripten DALi.
-if [ -z ${DESKTOP_PREFIX} ]; then
- echo "DESKTOP_PREFIX is required to build adaptor against dali-core. Please make sure you have sourced your setenv script (created by dali_env)."
- exit 1
-fi
-
-
-mkdir -p build
-cd build
-rm CMakeCache.txt
-
-/usr/bin/cmake .. -DCMAKE_BUILD_TYPE=Debug -DEMSCRIPTEN=1
-
-make -j8
-# On error, exit and return error.
-if [ $? -ne 0 ] ; then
- exit 1
-fi
-
-
-
-mv dali-emscripten dali-emscripten.bc
-
-# Non-optimised build.
-emcc dali-emscripten.bc -o dali-emscripten.html --memory-init-file 0 -s FULL_ES2=1 -s STB_IMAGE=1 -s ALLOW_MEMORY_GROWTH=1 -s ASSERTIONS=1 -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s EXPORT_NAME=\"dali\" -g4 --bind ; make -j8
-# On error, exit and return error.
-if [ $? -ne 0 ] ; then
- exit 1
-fi
-
-
-# Debug build.
-#emcc dali-emscripten.bc -o dali-emscripten.html --memory-init-file 0 -s FULL_ES2=1 -s STB_IMAGE=1 -s ALLOW_MEMORY_GROWTH=1 -s ASSERTIONS=2 -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s EXPORT_NAME=\"dali\" --js-opts 0 -g4 --bind
-
-# Optimised build.
-#emcc dali-emscripten.bc -o dali-emscripten.html -s FULL_ES2=1 -s STB_IMAGE=1 -s ALLOW_MEMORY_GROWTH=1 -s ASSERTIONS=0 -s DISABLE_EXCEPTION_CATCHING=2 -s EXPORT_NAME=\"dali\" -O2 --bind
-
-# Copy the required built artifacts to dali-env.
-mv ./dali-emscripten.js ${DESKTOP_PREFIX}/share/emscripten/
-mv ./dali-emscripten.html ${DESKTOP_PREFIX}/share/emscripten/
-
-# If static memory initialisation code was created in a separate file, copy this too.
-if [ -a ./dali-emcripten.html.mem ]; then
- mv ./dali-emscripten.html.mem ${DESKTOP_PREFIX}/share/emscripten/
-fi
if WEARABLE_PROFILE
libdali_adaptor_la_CXXFLAGS += \
$(HAPTIC_CFLAGS) \
- $(EFL_ASSIST_CFLAGS)
+ $(EFL_ASSIST_CFLAGS) \
$(APPCORE_WATCH_CFLAGS)
libdali_adaptor_la_LIBADD += \
-I../../../adaptors/public-api \
-I../../../adaptors/integration-api \
-I../../../adaptors/public-api/adaptor-framework \
+ -I../../../adaptors/devel-api/adaptor-framework \
-Werror -Wall
libdali_feedback_plugin_la_LIBADD = \
libdali_feedback_plugin_la_LDFLAGS = \
-rdynamic
-if MOBILE_PROFILE
-libdali_feedback_plugin_la_CXXFLAGS += \
- $(DEVICED_CFLAGS)
-
-libdali_feedback_plugin_la_LIBADD += \
- $(DEVICED_LIBS)
-endif
-
-if TV_PROFILE
-libdali_feedback_plugin_la_CXXFLAGS += \
- $(HAPTIC_CFLAGS)
-
-libdali_feedback_plugin_la_LIBADD += \
- $(HAPTIC_LIBS)
-endif
-
-if COMMON_PROFILE
-libdali_feedback_plugin_la_CXXFLAGS += \
- $(HAPTIC_CFLAGS)
-
-libdali_feedback_plugin_la_LIBADD += \
- $(HAPTIC_LIBS)
-endif
-
libdali_feedback_plugin_la_LIBADD += \
$(FEEDBACK_LIBS)
fi # enable_wayland
if test "x$enable_feedback" = "xyes"; then
-
-if test "x$enable_profile" = "xCOMMON" || test "x$enable_profile" = "xTV"; then
-PKG_CHECK_MODULES(HAPTIC, haptic)
-fi
-
-if test "x$enable_profile" = "xMOBILE"; then
-PKG_CHECK_MODULES(DEVICED, deviced)
-fi
+if test "x$enable_profile" != "xUBUNTU"; then
PKG_CHECK_MODULES(FEEDBACK, feedback)
PKG_CHECK_MODULES(MMFSOUND, mm-sound)
+fi # check UNBUNTU
fi # enable_feedback
AC_CONFIG_FILES(Makefile)
# performing a gbs build ( use gbs build -v to see it download location) E.g.
# http://download.tizen.org/snapshots/tizen/tv/tizen-tv/repos/arm-wayland/packages/repodata/xxxx-build.conf.gz
+# Do not provide .so automatically for the extensions.
+# This if statement is for backward compatibility with GBM/Obsolete build systems
+%if "%{?profile}" != "wearable" && "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%global __provides_exclude_from ^.*\\.(wearable|mobile|tv|ivi|common)$
+%endif
%bcond_with wayland
Name: dali-adaptor
Summary: The DALi Tizen Adaptor
-Version: 1.2.44
+Version: 1.2.46
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT
%define profile %{tizen_profile_name}
%endif
-%if "%{profile}" == "mobile"
-%define dali_profile MOBILE
-%define dali_feedback_plugin 0
-%define dali_videoplayer_plugin 1
-%define shaderbincache_flag DISABLE
-BuildRequires: pkgconfig(gles20)
-%define gles_requirement_setup 1
-%endif
-
-%if "%{profile}" == "tv"
-%define dali_profile TV
-%define dali_feedback_plugin 0
-%define dali_videoplayer_plugin 1
-%define shaderbincache_flag DISABLE
-BuildRequires: pkgconfig(glesv2)
-%define gles_requirement_setup 1
-%endif
-
-%if "%{profile}" == "wearable"
-%define dali_profile WEARABLE
-%define dali_feedback_plugin 0
-%define dali_videoplayer_plugin 1
-%define shaderbincache_flag DISABLE
-BuildRequires: pkgconfig(gles20)
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if wearable || "undefined"
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
BuildRequires: pkgconfig(capi-appfw-watch-application)
BuildRequires: pkgconfig(appcore-watch)
-%define gles_requirement_setup 1
%endif
-%if "%{profile}" == "ivi"
-%define dali_profile IVI
-%define dali_feedback_plugin 0
-%define dali_videoplayer_plugin 1
-%define shaderbincache_flag DISABLE
-BuildRequires: pkgconfig(glesv2)
-%define gles_requirement_setup 1
-%endif
-
-%if "%{profile}" == "common"
-%define dali_profile COMMON
-%define dali_feedback_plugin 0
-%define dali_videoplayer_plugin 1
-%define tizen_2_2_compatibility 0
-%define shaderbincache_flag DISABLE
+BuildRequires: pkgconfig(gles20)
BuildRequires: pkgconfig(glesv2)
-%define gles_requirement_setup 1
-%endif
-
-# If we have not set a BuildRequires for the gles version, default it here.
-%{!?gles_requirement_setup: BuildRequires: pkgconfig(glesv2)}
BuildRequires: pkgconfig
BuildRequires: gawk
BuildRequires: pkgconfig(harfbuzz)
BuildRequires: fribidi-devel
-%if 0%{?tizen_2_2_compatibility} != 1
BuildRequires: pkgconfig(capi-system-info)
BuildRequires: pkgconfig(capi-system-sensor)
-%endif
# Tizen currently does not have libuv as a separate libuv package
# So we have to look into the uv headers bundled inside node-js
BuildRequires: pkgconfig(wayland-egl)
BuildRequires: pkgconfig(wayland-client)
BuildRequires: wayland-devel
-# Currently Tizen Common we use does not have wayland extensions like xdg-shell
-%if "%{profile}" != "common"
BuildRequires: wayland-extension-client-devel
-%endif
# dali-adaptor-uv uses libuv mainloop and has its own wayland client (it needs wayland-client headers).
BuildRequires: libxkbcommon-devel
BuildRequires: pkgconfig(capi-appfw-application)
BuildRequires: pkgconfig(capi-system-system-settings)
-%if 0%{?over_tizen_2_2}
-BuildRequires: pkgconfig(capi-system-info)
+# for feedback plugin
+BuildRequires: pkgconfig(mm-sound)
+%if 0%{?tizen_version_major} >= 3
+BuildRequires: pkgconfig(feedback)
%endif
+# for videoplayer Plugin
+BuildRequires: pkgconfig(capi-media-player)
+
+# for multiprofile
+Requires: %{name}-compat = %{version}-%{release}
+Recommends: %{name}-profile_common = %{version}-%{release}
%description
The DALi Tizen Adaptor provides a Tizen specific implementation of the dali-core
platform abstraction and application shell
+###########################################
+# Dali adapter for profiles
+###########################################
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if mobile || "undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%package profile_mobile
+Summary: The DALi Tizen Adaptor for mobile
+Provides: %{name}-compat = %{version}-%{release}
+Conflicts: %{name}-profile_tv
+Conflicts: %{name}-profile_wearable
+Conflicts: %{name}-profile_ivi
+Conflicts: %{name}-profile_common
+%description profile_mobile
+The DALi Tizen Adaptor for mobile.
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if tv ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "common" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%package profile_tv
+Summary: The DALi Tizen Adaptor for tv
+Provides: %{name}-compat = %{version}-%{release}
+Conflicts: %{name}-profile_mobile
+Conflicts: %{name}-profile_wearable
+Conflicts: %{name}-profile_ivi
+Conflicts: %{name}-profile_common
+%description profile_tv
+The DALi Tizen Adaptor for tv.
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if wearable || "undefined"
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%package profile_wearable
+Summary: The DALi Tizen Adaptor for wearable
+Provides: %{name}-compat = %{version}-%{release}
+Conflicts: %{name}-profile_mobile
+Conflicts: %{name}-profile_tv
+Conflicts: %{name}-profile_ivi
+Conflicts: %{name}-profile_common
+%description profile_wearable
+The DALi Tizen Adaptor for wearable.
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if ivi ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "common" && "%{?profile}" != "mobile"
+%package profile_ivi
+Summary: The DALi Tizen Adaptor for ivi
+Provides: %{name}-compat = %{version}-%{release}
+Conflicts: %{name}-profile_mobile
+Conflicts: %{name}-profile_wearable
+Conflicts: %{name}-profile_tv
+Conflicts: %{name}-profile_common
+%description profile_ivi
+The DALi Tizen Adaptor for ivi.
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if common ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+# Currently Tizen Common we use does not have wayland extensions like xdg-shell
+%package profile_common
+%define tizen_2_2_compatibility 0
+Summary: The DALi Tizen Adaptor for common
+Provides: %{name}-compat = %{version}-%{release}
+Conflicts: %{name}-profile_mobile
+Conflicts: %{name}-profile_wearable
+Conflicts: %{name}-profile_tv
+Conflicts: %{name}-profile_ivi
+%description profile_common
+The DALi Tizen Adaptor for common.
+%endif
+
##############################
# devel
##############################
%package dali-feedback-plugin
Summary: Plugin to play haptic and audio feedback for Dali
Group: System/Libraries
-%if 0%{?dali_feedback_plugin}
-#Requires: libdeviced
-BuildRequires: pkgconfig(mm-sound)
-#BuildRequires: pkgconfig(haptic)
-BuildRequires: libfeedback-devel
-%endif
-
+Requires: %{name} = %{version}-%{release}
%description dali-feedback-plugin
Feedback plugin to play haptic and audio feedback for Dali
%package dali-video-player-plugin
Summary: Plugin to play a video file for Dali
Group: System/Libraries
-%if 0%{?dali_videoplayer_plugin}
-BuildRequires: pkgconfig(capi-media-player)
-%endif
-
%description dali-video-player-plugin
VideoPlayer plugin to play a video file for Dali
%endif
%endif
%define user_shader_cache_dir %{dali_data_ro_dir}/core/shaderbin/
-%define dali_plugin_sound_files %{dali_data_ro_dir}/plugins/sounds/
+%define dali_plugin_sound_files /plugins/sounds/
%define dev_include_path %{_includedir}
##############################
#--enable-appfw=yes \ # affects both dali-adaptor & dali-adaptor-uv
#--with-libuv=/usr/include/node/ \ # only affects dali-adaptor-uv
+
# Set up the build via configure.
-%configure --prefix=$PREFIX --with-jpeg-turbo --enable-gles=%{target_gles_version} --enable-shaderbincache=%{shaderbincache_flag} --enable-profile=%{dali_profile} \
-%if 0%{?dali_feedback_plugin}
+#######################################################################
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if mobile || "undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%configure --prefix=$PREFIX --with-jpeg-turbo --enable-gles=%{target_gles_version} \
+ --enable-shaderbincache=DISABLE --enable-profile=MOBILE \
+%if 0%{?tizen_version_major} >= 3
--enable-feedback \
%endif
-%if 0%{?dali_videoplayer_plugin}
--enable-videoplayer \
+%if 0%{?tizen_2_2_compatibility}
+ --with-tizen-2-2-compatibility \
+%endif
+%if %{with wayland}
+ --enable-efl=no \
+%else
+ --enable-efl=yes \
%endif
+%if 0%{?enable_debug}
+ --enable-debug \
+%endif
+ --enable-appfw=yes \
+ --with-libuv=/usr/include/node/ \
+ $configure_flags --libdir=%{_libdir}
+
+# Build.
+make %{?jobs:-j%jobs}
+
+pushd %{_builddir}/%{name}-%{version}/build/tizen
+%make_install DALI_DATA_RW_DIR="%{dali_data_rw_dir}" DALI_DATA_RO_DIR="%{dali_data_ro_dir}"
+popd
+
+pushd %{buildroot}%{_libdir}
+for FILE in libdali-adap*.so*; do mv "$FILE" "%{_builddir}/%{name}-%{version}/build/tizen/$FILE.mobile"; done
+popd
+
+%endif
+
+#######################################################################
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if tv ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "common" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%configure --prefix=$PREFIX --with-jpeg-turbo --enable-gles=%{target_gles_version} \
+ --enable-shaderbincache=DISABLE --enable-profile=TV \
+%if 0%{?tizen_version_major} >= 3
+ --enable-feedback \
+%endif
+ --enable-videoplayer \
%if 0%{?tizen_2_2_compatibility}
--with-tizen-2-2-compatibility \
%endif
# Build.
make %{?jobs:-j%jobs}
+pushd %{_builddir}/%{name}-%{version}/build/tizen
+%make_install DALI_DATA_RW_DIR="%{dali_data_rw_dir}" DALI_DATA_RO_DIR="%{dali_data_ro_dir}"
+popd
+
+pushd %{buildroot}%{_libdir}
+for FILE in libdali-adap*.so*; do mv "$FILE" "%{_builddir}/%{name}-%{version}/build/tizen/$FILE.tv"; done
+popd
+
+%endif
+
+#######################################################################
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if wearable || "undefined"
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%configure --prefix=$PREFIX --with-jpeg-turbo --enable-gles=%{target_gles_version} \
+ --enable-shaderbincache=DISABLE --enable-profile=WEARABLE \
+%if 0%{?tizen_version_major} >= 3
+ --enable-feedback \
+%endif
+ --enable-videoplayer \
+%if 0%{?tizen_2_2_compatibility}
+ --with-tizen-2-2-compatibility \
+%endif
+%if %{with wayland}
+ --enable-efl=no \
+%else
+ --enable-efl=yes \
+%endif
+%if 0%{?enable_debug}
+ --enable-debug \
+%endif
+ --enable-appfw=yes \
+ --with-libuv=/usr/include/node/ \
+ $configure_flags --libdir=%{_libdir}
+
+# Build.
+make %{?jobs:-j%jobs}
+
+pushd %{_builddir}/%{name}-%{version}/build/tizen
+%make_install DALI_DATA_RW_DIR="%{dali_data_rw_dir}" DALI_DATA_RO_DIR="%{dali_data_ro_dir}"
+popd
+
+pushd %{buildroot}%{_libdir}
+for FILE in libdali-adap*.so*; do mv "$FILE" "%{_builddir}/%{name}-%{version}/build/tizen/$FILE.wearable"; done
+popd
+
+%endif
+
+#######################################################################
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if ivi ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "common" && "%{?profile}" != "mobile"
+%configure --prefix=$PREFIX --with-jpeg-turbo --enable-gles=%{target_gles_version} \
+ --enable-shaderbincache=DISABLE --enable-profile=IVI \
+%if 0%{?tizen_version_major} >= 3
+ --enable-feedback \
+%endif
+ --enable-videoplayer \
+%if 0%{?tizen_2_2_compatibility}
+ --with-tizen-2-2-compatibility \
+%endif
+%if %{with wayland}
+ --enable-efl=no \
+%else
+ --enable-efl=yes \
+%endif
+%if 0%{?enable_debug}
+ --enable-debug \
+%endif
+ --enable-appfw=yes \
+ --with-libuv=/usr/include/node/ \
+ $configure_flags --libdir=%{_libdir}
+
+# Build.
+make %{?jobs:-j%jobs}
+
+pushd %{_builddir}/%{name}-%{version}/build/tizen
+%make_install DALI_DATA_RW_DIR="%{dali_data_rw_dir}" DALI_DATA_RO_DIR="%{dali_data_ro_dir}"
+popd
+
+pushd %{buildroot}%{_libdir}
+for FILE in libdali-adap*.so*; do mv "$FILE" "%{_builddir}/%{name}-%{version}/build/tizen/$FILE.ivi"; done
+popd
+
+%endif
+
+#######################################################################
+# common ( build dali_videoplayer_plugin for common uses )
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if common ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%configure --prefix=$PREFIX --with-jpeg-turbo --enable-gles=%{target_gles_version} \
+ --enable-shaderbincache=DISABLE --enable-profile=COMMON \
+%if 0%{?tizen_version_major} >= 3
+ --enable-feedback \
+%endif
+ --enable-videoplayer \
+%if 0%{?tizen_2_2_compatibility}
+ --with-tizen-2-2-compatibility \
+%endif
+%if %{with wayland}
+ --enable-efl=no \
+%else
+ --enable-efl=yes \
+%endif
+%if 0%{?enable_debug}
+ --enable-debug \
+%endif
+ --enable-appfw=yes \
+ --with-libuv=/usr/include/node/ \
+ $configure_flags --libdir=%{_libdir}
+
+# Build.
+make %{?jobs:-j%jobs}
+%endif
+
+
##############################
# Installation
##############################
%install
rm -rf %{buildroot}
-cd build/tizen
+
+pushd %{_builddir}/%{name}-%{version}/build/tizen
%make_install DALI_DATA_RW_DIR="%{dali_data_rw_dir}" DALI_DATA_RO_DIR="%{dali_data_ro_dir}"
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# !unified && (wearable || tv || ivi || mobile)
+%if "%{?profile}" == "wearable" || "%{?profile}" == "tv" || "%{?profile}" == "ivi" || "%{?profile}" == "mobile"
+rm -rf %{buildroot}%{_libdir}/libdali-adap*.so*
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# wearable || tv || ivi || mobile || unified
+%if "%{?profile}" != "common"
+for FILE in libdali-*.so*; do mv "$FILE" "%{buildroot}%{_libdir}/$FILE"; done
+%endif
+popd
+
##############################
# Upgrade order:
# 1 - Pre Install new package
/sbin/ldconfig
exit 0
-%if 0%{?dali_feedback_plugin}
-%post dali-feedback-plugin
+##############################
+# Pre Uninstall old package
+##############################
+%preun
+exit 0
+
+##############################
+# Post Uninstall old package
+##############################
+%postun
/sbin/ldconfig
exit 0
-%endif
%if %{with wayland}
-%if 0%{?dali_videoplayer_plugin}
%post dali-video-player-plugin
/sbin/ldconfig
exit 0
%endif
+
+%if %{with wayland}
+%postun dali-video-player-plugin
+/sbin/ldconfig
+exit 0
%endif
+
##############################
-# Pre Uninstall old package
-##############################
-%preun
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if mobile || "undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%post profile_mobile
+pushd %{_libdir}
+for FILE in libdali-adap*.so*.mobile; do ln -sf "$FILE" "${FILE%.mobile}"; done
+popd
+/sbin/ldconfig
exit 0
+%postun profile_mobile
+/sbin/ldconfig
+exit 0
+%endif
+
##############################
-# Post Uninstall old package
-##############################
-%postun
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if tv ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "common" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%post profile_tv
+pushd %{_libdir}
+for FILE in libdali-adap*.so*.tv; do ln -sf "$FILE" "${FILE%.tv}"; done
+popd
/sbin/ldconfig
exit 0
-%if 0%{?dali_feedback_plugin}
-%postun dali-feedback-plugin
+%postun profile_tv
/sbin/ldconfig
exit 0
%endif
-%if %{with wayland}
-%if 0%{?dali_videoplayer_plugin}
-%postun dali-video-player-plugin
+##############################
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if wearable || "undefined"
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%post profile_wearable
+pushd %{_libdir}
+for FILE in libdali-adap*.so*.wearable; do ln -sf "$FILE" "${FILE%.wearable}"; done
+popd
+/sbin/ldconfig
+exit 0
+
+%postun profile_wearable
/sbin/ldconfig
exit 0
%endif
+
+##############################
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if ivi ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "common" && "%{?profile}" != "mobile"
+%post profile_ivi
+pushd %{_libdir}
+for FILE in libdali-adap*.so*.ivi; do ln -sf "$FILE" "${FILE%.ivi}"; done
+popd
+/sbin/ldconfig
+exit 0
+
+%postun profile_ivi
+/sbin/ldconfig
+exit 0
%endif
+
##############################
# Files in Binary Packages
##############################
%files
%manifest dali-adaptor.manifest
%defattr(-,root,root,-)
-%{_libdir}/libdali-adap*.so*
%defattr(-,app,app,-)
%dir %{user_shader_cache_dir}
%{_bindir}/*
%license LICENSE
-%files devel
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if common ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
%defattr(-,root,root,-)
-%{dev_include_path}/dali/dali.h
-%{dev_include_path}/dali/public-api/*
-%{dev_include_path}/dali/devel-api/*
-%{dev_include_path}/dali/doc/*
-%{_libdir}/pkgconfig/dali-adaptor.pc
-%{_libdir}/pkgconfig/dali-adaptor-uv.pc
+%{_libdir}/libdali-adap*.so*
+%exclude %{_libdir}/libdali-adap*.so*.mobile
+%exclude %{_libdir}/libdali-adap*.so*.wearable
+%exclude %{_libdir}/libdali-adap*.so*.tv
+%exclude %{_libdir}/libdali-adap*.so*.ivi
+%endif
-%files integration-devel
+%if %{with wayland}
+%files dali-video-player-plugin
+%manifest dali-adaptor.manifest
%defattr(-,root,root,-)
-%{dev_include_path}/dali/integration-api/adaptors/*
-%{_libdir}/pkgconfig/dali-adaptor-integration.pc
+%{_libdir}/libdali-video-player-plugin.so*
+%license LICENSE
+%endif
-%if 0%{?dali_feedback_plugin}
+%if 0%{?tizen_version_major} >= 3
%files dali-feedback-plugin
+%manifest dali-adaptor.manifest
%defattr(-,root,root,-)
%{_libdir}/libdali-feedback-plugin.so*
%{dali_plugin_sound_files}/*
%endif
-%if %{with wayland}
-%if 0%{?dali_videoplayer_plugin}
-%files dali-video-player-plugin
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if common ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%files profile_common
+# default .so files are housed in the main pkg.
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if mobile || "undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%files profile_mobile
%manifest dali-adaptor.manifest
%defattr(-,root,root,-)
-%{_libdir}/libdali-video-player-plugin.so*
-%license LICENSE
+%{_libdir}/libdali-adap*.so*.mobile
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if tv ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "common" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%files profile_tv
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libdali-adap*.so*.tv
%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if wearable || "undefined"
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%files profile_wearable
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libdali-adap*.so*.wearable
+%endif
+
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if ivi ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "common" && "%{?profile}" != "mobile"
+%files profile_ivi
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libdali-adap*.so*.ivi
%endif
+
+
+%files devel
+%defattr(-,root,root,-)
+%{dev_include_path}/dali/dali.h
+%{dev_include_path}/dali/public-api/*
+%{dev_include_path}/dali/devel-api/*
+%{dev_include_path}/dali/doc/*
+%{_libdir}/pkgconfig/dali-adaptor.pc
+%{_libdir}/pkgconfig/dali-adaptor-uv.pc
+
+%files integration-devel
+%defattr(-,root,root,-)
+%{dev_include_path}/dali/integration-api/adaptors/*
+%{_libdir}/pkgconfig/dali-adaptor-integration.pc
+++ /dev/null
-/*
- * Copyright (c) 2015 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 "emscripten-callbacks.h"
-
-// EXTERNAL INCLUDES
-#include <vector>
-#include <dali/public-api/dali-core.h>
-#include "emscripten/emscripten.h"
-#include "emscripten/bind.h"
-#include "emscripten/val.h"
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-Statistics stats;
-
-// Javascript callbacks
-
-// Allows the adaptor to get a glyph image from the browser
-emscripten::val JSGetGlyphImage(emscripten::val::null());
-
-// Allows the adaptor to request an image from the browser
-emscripten::val JSGetImage(emscripten::val::null());
-
-// Allows the adaptor to get image meta data
-emscripten::val JSGetImageMetaData(emscripten::val::null());
-
-// Signals to the browser the end of rendering
-emscripten::val JSRenderFinished(emscripten::val::null());
-
-
-Integration::BitmapPtr GetGlyphImage( const std::string& fontFamily, const std::string& fontStyle, float fontSize, uint32_t character )
-{
- Integration::BitmapPtr ret;
-
- // causes exception in browser if callback isnt set to a function;
- emscripten::val val = JSGetGlyphImage(fontFamily,
- fontStyle,
- fontSize,
- character);
-
- std::vector<unsigned char> data = emscripten::vecFromJSArray<unsigned char>(val);
-
- int step = fontSize * 4;
-
- if( data.size() )
- {
- Integration::Bitmap* bitmap = Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS,
- ResourcePolicy::OWNED_DISCARD); // dali manages buffer
-
- if(bitmap)
- {
- Integration::Bitmap::PackedPixelsProfile* profile = bitmap->GetPackedPixelsProfile();
-
- if(profile)
- {
- std::vector<unsigned char> *buffer = new std::vector<unsigned char>;
-
- buffer->reserve( fontSize * fontSize );
-
- // take only alpha
- for(int y = 0; y < fontSize; ++y)
- {
- for(int x = 0; x < step; x+=4)
- {
- buffer->push_back(data[ x + (y*step) +3]);
- }
- }
-
- if( buffer )
- {
- profile->AssignBuffer(Pixel::A8,
- &(*buffer)[0],
- (*buffer).size(),
- fontSize,
- fontSize);
- }
-
- ret = Integration::BitmapPtr( bitmap );
- }
- else
- {
- printf("bitmap has no packedpixelsprofile\n");
- }
- }
- else
- {
- printf("bitmap not created\n");
- }
- }
- else
- {
- printf("Image data from javascript is empty\n");
- }
-
- return ret;
-}
-
-
-Integration::BitmapPtr GetImage( const Dali::ImageDimensions& size,
- const Dali::FittingMode::Type& scalingMode,
- const Dali::SamplingMode::Type& samplingMode,
- const bool orientationCorrection,
- const std::string& filename )
-{
- Integration::BitmapPtr ret;
-
- // causes exception in browser if callback isnt set to a function;
- emscripten::val val = JSGetImage(filename);
-
- emscripten::val array = val["array"];
- int w = val["x"].as<int>();
- int h = val["y"].as<int>();
-
- std::vector<unsigned char> data = emscripten::vecFromJSArray<unsigned char>(array);
-
- Integration::Bitmap* bitmap = Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS,
- Dali::ResourcePolicy::OWNED_DISCARD); // dali manages buffer
-
- if(bitmap)
- {
- Integration::Bitmap::PackedPixelsProfile* profile = bitmap->GetPackedPixelsProfile();
-
- if(profile)
- {
- std::vector<unsigned char> *buffer = new std::vector<unsigned char>(data.begin(), data.end());
-
- if( buffer )
- {
- profile->AssignBuffer(Pixel::RGBA8888,
- &(*buffer)[0],
- (*buffer).size(),
- w,
- h);
- }
-
- ret = Integration::BitmapPtr( bitmap );
- }
- else
- {
- printf("bitmap has no packedpixelsprofile\n");
- }
- }
- else
- {
- printf("bitmap not created\n");
- }
-
- return ret;
-}
-
-Dali::ImageDimensions LoadImageMetadata(const std::string filename,
- Dali::ImageDimensions& size,
- Dali::FittingMode::Type fittingMode,
- Dali::SamplingMode::Type samplingMode,
- bool orientationCorrection )
-{
- emscripten::val val = JSGetImageMetaData(filename);
-
- // @todo
- // size.x = val["w"]
- // size.y = val["h"]
- //
- return Dali::ImageDimensions();
-}
-
-void RenderFinished()
-{
- if (JSRenderFinished.typeof().as<std::string>() == "function")
- {
- emscripten::val val = JSRenderFinished();
- }
-}
-
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
+++ /dev/null
-#ifndef __DALI_EMSCRIPTEN_CALLBACKS_H__
-#define __DALI_EMSCRIPTEN_CALLBACKS_H__
-
-/*
- * Copyright (c) 2015 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/integration-api/platform-abstraction.h>
-#include <dali/public-api/common/dali-common.h>
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Internal
-{
-namespace Emscripten
-{
-
-/**
- * Glyph helper
- *
- * Allows Dali adaptor to request a glyph image from the browser
- *
- * @param[in] fontFamily The font family name
- * @param[in] fontStyle The font style name
- * @param[in] fontSize The font size
- * @param[in] character The character
- *
- */
-Dali::Integration::BitmapPtr GetGlyphImage( const std::string& fontFamily, const std::string& fontStyle, float fontSize, uint32_t character );
-
-/**
- * Image meta data helper
- *
- * Allows Dali adaptor to request image metadata from image known to the browser
- *
- * @param[in] filename The image name (possibly not directly a filename due to the browser sandboxing)
- * @param[in] size The image dimensions
- * @param[in] fittingMode The dali fitting mode
- * @param[in] samplingMode The dali sampling mode
- * @param[in] orientationCorrection The orientation correction
- *
- */
-Dali::ImageDimensions LoadImageMetadata(const std::string filename,
- Dali::ImageDimensions& size,
- Dali::FittingMode::Type fittingMode,
- Dali::SamplingMode::Type samplingMode,
- bool orientationCorrection );
-
-/**
- * Image helper
- *
- * Allows Dali adaptor to request an image from the browser
- *
- * @param[in] size The image dimensionsn
- * @param[in] fittingMode The dali fitting mode
- * @param[in] samplingMode The dali sampling mode
- * @param[in] orientationCorrection The orientation correction
- * @param[in] filename The image name (possibly not directly a filename due to the browser sandboxing)
- *
- */
-Dali::Integration::BitmapPtr GetImage(const Dali::ImageDimensions& size,
- const Dali::FittingMode::Type& fittingMode,
- const Dali::SamplingMode::Type& samplingMode,
- const bool orientationCorrection,
- const std::string& filename );
-
-/**
- * Debug statistics for the browser
- *
- */
-struct Statistics
-{
- bool on;
- float frameCount;
-
- float lastFrameDeltaSeconds;
- unsigned int lastSyncTimeMilliseconds;
- unsigned int nextSyncTimeMilliseconds;
-
- unsigned int keepUpdating; ///< A bitmask of KeepUpdating values
- bool needsNotification;
- float secondsFromLastFrame;
-
-Statistics() :on(true),
- frameCount(0.0),
- lastFrameDeltaSeconds(0.0),
- lastSyncTimeMilliseconds(0.0),
- nextSyncTimeMilliseconds(0.0),
- keepUpdating(0),
- needsNotification(false),
- secondsFromLastFrame(0.0)
- {};
-};
-
-extern Statistics stats;
-
-}; // namespace Emscripten
-}; // namespace Internal
-}; // namespace Dali
-
-#endif // header
+++ /dev/null
-/*
- * Copyright (c) 2016 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 "emscripten-platform-abstraction.h"
-
-// EXTERNAL INCLUDES
-#include <set>
-#include <stdint.h>
-#include <cstring>
-#include <SDL_surface.h>
-#include <SDL_image.h>
-#include "emscripten/emscripten.h"
-#include "emscripten-callbacks.h"
-
-#define EM_LOG(x); // EM_ASM( console.log( x ) );
-
-
-// INTERNAL INCLUDES
-#include <dali/integration-api/platform-abstraction.h>
-#include <dali/devel-api/common/ref-counted-dali-vector.h>
-
-namespace
-{
-
-Dali::Integration::BitmapPtr LoadResourceEncodedImage( Dali::RefCountedVector<uint8_t>* encodedBlob )
-{
- Dali::Integration::BitmapPtr bitmapPtr = NULL;
-
- if( encodedBlob != 0 )
- {
- const size_t blobSize = encodedBlob->GetVector().Size();
- uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
- DALI_ASSERT_DEBUG( blobSize > 0U );
- DALI_ASSERT_DEBUG( blobBytes != 0U );
-
- if( blobBytes != 0 && blobSize > 0U )
- {
-
- SDL_RWops *memory = SDL_RWFromMem(blobBytes, blobSize);
-
- if(!memory)
- {
- printf(" Error Null pointer from SDL RW memory?\n");
- }
-
- SDL_Surface *surface = IMG_Load_RW(memory, 0);
-
- if(surface)
- {
- bitmapPtr = Dali::Integration::Bitmap::New( Dali::Integration::Bitmap::BITMAP_2D_PACKED_PIXELS,
- Dali::ResourcePolicy::OWNED_DISCARD ); // DISCARD; Dali manages
-
- Dali::Integration::Bitmap::PackedPixelsProfile* packedProfile = bitmapPtr->GetPackedPixelsProfile();
- DALI_ASSERT_ALWAYS(packedProfile);
-
- unsigned char bytesPerPixel = surface->format->BytesPerPixel;
-
- Dali::Integration::PixelBuffer* pixels = NULL;
-
- unsigned char targetBytesPerPixel = 3; // bytesPerPixel;
-
- // SDL in emscripten returns us a 4byteperpixel image regardless of rgb/png etc
- // Theres no apparent way to differentiate an image with an alpha channel
- // In Dali if an image has an alpha channel it gets sorted. This introduces odd artifacts on rotation
- // as the sorting algorithm presumes front on view.
- // So here well just support pngs with an alpha channel.
- // We're poking around in the format as emscripten currently lacks a file memory api where we could use
- // Dali's machinery to read the format.
- unsigned char *pBytes = blobBytes;
-
- if( 0x89 == *(pBytes+0) && 0x50 == *(pBytes+1) ) // magic bytes for png_all_filters
- {
- pBytes+=8; // 8 bytes for header
- pBytes+=4; // 4 bytes for chunk length
- pBytes+=4; // 4 bytes for chunk type
- // ihdr data (must be first chunk)
- pBytes+=4; // 4 for width,height
- pBytes+=4;
- pBytes+=1; // 1 for bit depth
- unsigned char ihdr_colorType= *pBytes; // 1 for bit colorType
- if( (4 == ihdr_colorType || // 4 is 8,16 bit depth with alpha LA
- 6 == ihdr_colorType) ) // 6 is 8,16 bit depth with alpha RGBA
- {
- targetBytesPerPixel = 4;
- }
- }
-
- if(3 == targetBytesPerPixel)
- {
- pixels = packedProfile->ReserveBuffer(Dali::Pixel::RGB888,
- surface->w, surface->h,
- surface->w, surface->h);
- }
- else if(4 == targetBytesPerPixel)
- {
- pixels = packedProfile->ReserveBuffer(Dali::Pixel::RGBA8888,
- surface->w, surface->h,
- surface->w, surface->h);
- }
- else
- {
- DALI_ASSERT_ALWAYS(0 && "bad bytes per pixel");
- }
-
- unsigned char* fromPtr = static_cast<unsigned char*>(surface->pixels);
-
- int stride = surface->pitch;
- int index = 0;
- for(int h = 0; h < surface->h; ++h)
- {
- for(int w = 0; w < (surface->w*bytesPerPixel); w+=bytesPerPixel)
- {
- for(int j = 0; j < targetBytesPerPixel; ++j)
- {
- pixels[ index++ ] = *( (fromPtr + (h * stride) ) + w + j );
- }
- }
- }
- } // if surface
- else
- {
- printf(" Error empty surface when decoding image? (SDL RW Memory ptr=%llx) %s. %d\n", (long long)(memory), SDL_GetError(), blobSize);
- }
-
- } // if blobSize
- else
- {
- printf(" Error No bytes in image?\n");
- }
-
- } // if encodedBlob
- else
- {
- printf(" Error Null pointer given for decoding image?\n");
- }
-
- if(bitmapPtr)
- {
- int x = 0;
- EM_ASM( console.log( "LoadResourceEncodedImage: Image:-" ) );
- x = EM_ASM_INT({
- console.log( $0 ) }, bitmapPtr->GetImageWidth() );
- x = EM_ASM_INT({
- console.log( $0 ) }, bitmapPtr->GetImageHeight() );
- x = EM_ASM_INT({
- console.log( $0 ) }, bitmapPtr->GetBufferSize() );
-
- }
- else
- {
- EM_ASM( console.log( "LoadResourceEncodedImage: no bitmap data?" ) );
- }
-
- return bitmapPtr;
-}
-
-} // anon namespace
-
-namespace Dali
-{
-
-EmscriptenPlatformAbstraction::EmscriptenPlatformAbstraction()
- :
- mSize(10,10)
-{
-}
-
-
-EmscriptenPlatformAbstraction::~EmscriptenPlatformAbstraction()
-{
-}
-
-void EmscriptenPlatformAbstraction::GetTimeMicroseconds(unsigned int &seconds, unsigned int µSeconds)
-{
- double current = EM_ASM_DOUBLE_V({ return new Date().getTime(); }); // getTime() in ms
-
- seconds = static_cast<unsigned int>(current/1000.0);
- microSeconds = (static_cast<unsigned int>(current) - seconds*1000.0) * 1000;
-}
-
-ImageDimensions EmscriptenPlatformAbstraction::GetClosestImageSize( const std::string& filename,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection )
-{
- return Dali::Internal::Emscripten::LoadImageMetadata(filename, size, fittingMode, samplingMode, orientationCorrection);
-}
-
-ImageDimensions EmscriptenPlatformAbstraction::GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection )
-{
- // @todo
- return Dali::ImageDimensions(); // Dali::Internal::Emscripten::LoadImageMetadata(filename, size, fittingMode, samplingMode, orientationCorrection);
-}
-
-Integration::ResourcePointer EmscriptenPlatformAbstraction::LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath )
-{
- Integration::ResourcePointer ret;
-
- switch(resourceType.id)
- {
- case Integration::ResourceBitmap:
- {
- const Integration::BitmapResourceType& bitmapResource( static_cast<const Integration::BitmapResourceType&>(resourceType) );
-
- Integration::BitmapPtr bitmapPtr = Dali::Internal::Emscripten::GetImage( bitmapResource.size,
- bitmapResource.scalingMode,
- bitmapResource.samplingMode,
- bitmapResource.orientationCorrection,
- resourcePath );
-
- ret = bitmapPtr;
- }
- break;
- } // switch(resourceType->id)
-
- return ret;
-}
-
-Integration::BitmapPtr EmscriptenPlatformAbstraction::DecodeBuffer( const Integration::ResourceType& resourceType, uint8_t * buffer, size_t bufferSize )
-{
- return Integration::BitmapPtr();
-}
-
-
-bool EmscriptenPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
-{
- EM_LOG("EmscriptenPlatformAbstraction::LoadShaderBinaryFile");
- return false;
-}
-
-void EmscriptenPlatformAbstraction::UpdateDefaultsFromDevice()
-{
- DALI_ASSERT_ALWAYS("!Unimplemented");
- mGetDefaultFontFamilyResult+=1.0f;
-}
-
-void EmscriptenPlatformAbstraction::IncrementGetTimeResult(size_t milliseconds)
-{
-}
-
-} // Dali
+++ /dev/null
-#ifndef __DALI_EMSCRIPTEN_PLATFORM_ABSTRACTION_H__
-#define __DALI_EMSCRIPTEN_PLATFORM_ABSTRACTION_H__
-
-/*
- * Copyright (c) 2016 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 <set>
-#include <stdint.h>
-#include <cstring>
-#include <queue>
-
-// INTERNAL INCLUDES
-#include <dali/integration-api/platform-abstraction.h>
-#include <dali/integration-api/bitmap.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-
-typedef IntrusivePtr<Dali::RefObject> ResourcePointer;
-} // namespace Integration
-
-/**
- * An Dali Platform abstraction using libSDL for Emscripten.
- *
- * Emscripten already wraps the SDL API so we can use this API to create windows/canvas in the browser
- *
- */
-class DALI_IMPORT_API EmscriptenPlatformAbstraction : public Dali::Integration::PlatformAbstraction
-{
-
-public:
-
- struct LoadFileResult
- {
- LoadFileResult()
- : loadResult(false)
- {
-
- }
-
- bool loadResult;
- std::vector< unsigned char> buffer;
- };
-
-
- /**
- * Constructor
- */
- EmscriptenPlatformAbstraction();
-
-
- /**
- * Destructor
- */
- virtual ~EmscriptenPlatformAbstraction();
-
- /**
- * @copydoc PlatformAbstraction::GetTimeMicroseconds()
- */
- virtual void GetTimeMicroseconds(unsigned int &seconds, unsigned int µSeconds);
-
- void IncrementGetTimeResult(size_t milliseconds);
-
- /**
- * @copydoc PlatformAbstraction::GetClosestImageSize()
- */
- virtual ImageDimensions GetClosestImageSize( const std::string& filename,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection );
- /**
- * @copydoc PlatformAbstraction::GetClosestImageSize()
- */
- virtual ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
- ImageDimensions size,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection );
-
- /**
- * @copydoc PlatformAbstraction::LoadResourceSynchronously()
- */
- virtual Integration::ResourcePointer LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath );
-
- /**
- * @copydoc PlatformAbstraction::DecodeBuffer()
- */
- virtual Integration::BitmapPtr DecodeBuffer( const Integration::ResourceType& resourceType, uint8_t * buffer, size_t bufferSize );
-
- /**
- * @copydoc PlatformAbstraction::LoadShaderBinaryFile()
- */
- virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
-
- /**
- * @copydoc PlatformAbstraction::SaveShaderBinaryFile()
- */
- virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const;
-
- /**
- * @copydoc PlatformAbstraction::UpdateDefaultsFromDevice()
- */
- virtual void UpdateDefaultsFromDevice();
-
-private:
- std::string mGetDefaultFontFamilyResult;
- Vector2 mSize;
-
- LoadFileResult mLoadFileResult;
-
- typedef std::pair< Integration::ResourceId, Integration::BitmapPtr > ResourceIdBitmapPair;
- std::queue<ResourceIdBitmapPair> mResourceQueue;
-
-};
-
-} // Dali
-
-#endif /* __DALI_TET_PLATFORM_ABSTRACTION_H__ */
+++ /dev/null
-# Add local source files here:
-
-slp_platform_abstraction_src_files = \
- $(slp_platform_abstraction_src_dir)/emscripten-callbacks.cpp \
- $(slp_platform_abstraction_src_dir)/emscripten-platform-abstraction.cpp
-
-slp_assimp_src_files =
-
-slp_assimp_stub_src_files =
-
-# Add public headers here:
-
-# platform_abstraction_header_files =
--- /dev/null
+/*
+ * Copyright (c) 2017 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 "pixel-manipulation.h"
+#include "alpha-mask.h"
+#include "pixel-buffer-impl.h"
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+
+void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& mask )
+{
+ const float rowFactor = float(mask.GetHeight()) / (1.0f * buffer.GetHeight());
+ const float colFactor = float(mask.GetWidth()) / (1.0f * buffer.GetWidth()) ;
+
+ int numSamples = 1;
+ if( mask.GetHeight() > buffer.GetHeight() || mask.GetWidth() > buffer.GetWidth() )
+ {
+ numSamples = 4;
+ }
+
+ int srcAlphaByteOffset=0;
+ int srcAlphaMask=0;
+ Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
+
+ Channel alphaChannel = ALPHA;
+ if( Pixel::HasAlpha(srcPixelFormat) )
+ {
+ Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
+ }
+ else if( srcPixelFormat == Pixel::L8 )
+ {
+ srcAlphaMask=0xFF;
+ alphaChannel = LUMINANCE;
+ }
+
+ int destAlphaByteOffset=0;
+ int destAlphaMask=0;
+ Dali::Pixel::GetAlphaOffsetAndMask( buffer.GetPixelFormat(), destAlphaByteOffset, destAlphaMask );
+
+ unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
+ int srcStride = mask.GetWidth() * srcBytesPerPixel;
+ unsigned char* srcBuffer = mask.GetBuffer();
+ unsigned char* destBuffer = buffer.GetBuffer();
+
+ unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( buffer.GetPixelFormat() );
+
+ int srcOffset=0;
+ int destOffset=0;
+
+ float srcAlphaValue = 1.0f;
+
+ for( unsigned int row = 0; row < buffer.GetHeight(); ++row )
+ {
+ for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
+ {
+ if( numSamples == 1 )
+ {
+ srcOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
+ unsigned char alpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+ srcAlphaValue = float(alpha)/255.0f;
+ }
+ else
+ {
+ srcAlphaValue = ReadWeightedSample( srcBuffer, srcPixelFormat, srcStride, col*colFactor, row*rowFactor, mask.GetWidth(), mask.GetHeight(), alphaChannel );
+ }
+
+ unsigned char destAlpha = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
+ float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
+ destAlpha = destAlphaValue;
+ destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
+ destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
+
+ destOffset += destBytesPerPixel;
+ }
+ }
+}
+
+PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& mask )
+{
+ const float rowFactor = float(mask.GetHeight()) / (1.0f * buffer.GetHeight());
+ const float colFactor = float(mask.GetWidth()) / (1.0f * buffer.GetWidth()) ;
+
+ int numSamples = 1;
+ if( mask.GetHeight() > buffer.GetHeight() || mask.GetWidth() > buffer.GetWidth() )
+ {
+ numSamples = 4;
+ }
+
+ // Set up source alpha offsets
+ int srcAlphaByteOffset=0;
+ int srcAlphaMask=0;
+ Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
+ Channel alphaChannel = ALPHA;
+ if( Pixel::HasAlpha(srcPixelFormat) )
+ {
+ Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
+ }
+ else if( srcPixelFormat == Pixel::L8 )
+ {
+ srcAlphaMask=0xFF;
+ alphaChannel = LUMINANCE;
+ }
+
+ unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
+ int srcStride = mask.GetWidth() * srcBytesPerPixel;
+ unsigned char* srcBuffer = mask.GetBuffer();
+
+ // Set up source color offsets
+ Dali::Pixel::Format srcColorPixelFormat = buffer.GetPixelFormat();
+ unsigned int srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcColorPixelFormat );
+
+ // Setup destination offsets
+ Dali::Pixel::Format destPixelFormat = Dali::Pixel::RGBA8888;
+ unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( destPixelFormat );
+ int destAlphaByteOffset=0;
+ int destAlphaMask=0;
+ Dali::Pixel::GetAlphaOffsetAndMask( destPixelFormat, destAlphaByteOffset, destAlphaMask );
+
+ PixelBufferPtr newPixelBuffer = PixelBuffer::New( buffer.GetWidth(), buffer.GetHeight(),
+ destPixelFormat );
+ unsigned char* destBuffer = newPixelBuffer->GetBuffer();
+
+ unsigned char* oldBuffer = buffer.GetBuffer();
+
+ int srcAlphaOffset=0;
+ int srcColorOffset=0;
+ int destOffset=0;
+ bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
+
+ float srcAlphaValue = 1.0f;
+ unsigned char destAlpha = 0;
+
+ for( unsigned int row = 0; row < buffer.GetHeight(); ++row )
+ {
+ for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
+ {
+ if( numSamples == 1 )
+ {
+ srcAlphaOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
+ unsigned char alpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
+ srcAlphaValue = float(alpha)/255.0f;
+ }
+ else
+ {
+ srcAlphaValue = ReadWeightedSample( srcBuffer, srcPixelFormat, srcStride, col*colFactor, row*rowFactor, mask.GetWidth(), mask.GetHeight(), alphaChannel );
+ }
+
+ ConvertColorChannelsToRGBA8888(oldBuffer, srcColorOffset, srcColorPixelFormat, destBuffer, destOffset );
+
+ if( hasAlpha )
+ {
+ destAlpha = ConvertAlphaChannelToA8( oldBuffer, srcColorOffset, srcColorPixelFormat );
+ float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
+ destAlpha = destAlphaValue;
+ }
+ else
+ {
+ destAlpha = floorf(Clamp(srcAlphaValue * 255.0f, 0.0f, 255.0f));
+ }
+
+ destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
+ destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
+
+ srcColorOffset += srcColorBytesPerPixel;
+ destOffset += destBytesPerPixel;
+ }
+ }
+
+ return newPixelBuffer;
+}
+
+
+float ReadWeightedSample( unsigned char* buffer, Pixel::Format pixelFormat, int stride, float x, float y, int width, int height, Channel alphaChannel )
+{
+ int srcRow = floorf( y );
+ int srcCol = floorf( x );
+
+ int bytesPerPixel = Dali::Pixel::GetBytesPerPixel( pixelFormat );
+ int srcOffset = srcRow * stride + srcCol * bytesPerPixel;
+ float samples[4];
+
+ samples[0] = ReadChannel( buffer + srcOffset, pixelFormat, alphaChannel );
+
+ if( srcCol < width-1 )
+ {
+ samples[1] = ReadChannel( buffer + srcOffset+bytesPerPixel, pixelFormat, alphaChannel );
+ }
+ else
+ {
+ samples[1] = samples[0];
+ }
+
+ if( srcRow < height-1 )
+ {
+ samples[2] = ReadChannel( buffer + stride + srcOffset, pixelFormat, alphaChannel );
+ }
+ else
+ {
+ samples[2] = samples[0];
+ }
+
+ if( srcRow < height-1 && srcCol < width-1 )
+ {
+ samples[3] = ReadChannel( buffer + stride + srcOffset + bytesPerPixel, pixelFormat, alphaChannel );
+ }
+ else
+ {
+ samples[3] = samples[2];
+ }
+
+ // Bilinear interpolation:
+ float weight[4];
+ weight[0] = float(srcRow+1.0f) - y;
+ weight[1] = y - float(srcRow);
+ weight[2] = float(srcCol+1.0f) - x;
+ weight[3] = x - float(srcCol);
+
+ return ( weight[2] * (samples[0] * weight[0] + samples[1] * weight[1]) +
+ weight[3] * (samples[2] * weight[0] + samples[3] * weight[1]) ) / 255.0f;
+}
+
+} //namespace Adaptor
+
+}// namespace Internal
+
+}// namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_ADAPTOR_ALPHA_MASK_H
+#define DALI_INTERNAL_ADAPTOR_ALPHA_MASK_H
+
+/*
+ * Copyright (c) 2017 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 "pixel-buffer-impl.h"
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+
+/**
+ * Apply the mask to a buffer's alpha channel
+ * @param[in] buffer The buffer to apply the mask to
+ * @param[in] mask The mask to apply
+ */
+void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& mask );
+
+/**
+ * Create a new PixelBuffer with an alpha channel large enough to handle the alpha from
+ * the mask, converting the color values to the new size, and either multiplying the mask's
+ * alpha into the existing alpha value, or writing the mask's alpha value directly into
+ * the new buffer's alpha channel.
+ *
+ * @param[in] buffer The buffer to apply the mask to
+ * @param[in] mask The mask to apply
+ * @return A new pixel buffer containing the masked image
+ */
+PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& mask );
+
+/**
+ * Read a weighted sample from the given channel for a given coordinate
+ * @param[in] buffer The buffer to read from
+ * @param[in] pixelFormat The pixel format of the buffer
+ * @param[in] stride The stride across the buffer
+ * @param[in] x The x coordinate to sample from
+ * @param[in] y The y coordinate to sample from
+ * @param[in] width The width of the buffer in pixels
+ * @param[in] height The height of the buffer in pixels
+ * @param[in] channel The channel to read from
+ * @return An averaged value from the 4 pixels around the given coordinate
+ */
+float ReadWeightedSample( unsigned char* buffer, Pixel::Format pixelFormat, int stride, float x, float y, int width, int height, Channel channel );
+
+} //namespace Adaptor
+} //namespace Internal
+} //namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_ALPHA_MASK_H
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/math/vector2.h>
#include <resampler.h>
+#include <image-loading.h>
// INTERNAL INCLUDES
// Constants used by the ImageResampler.
const float DEFAULT_SOURCE_GAMMA = 1.75f; ///< Default source gamma value used in the Resampler() function. Partial gamma correction looks better on mips. Set to 1.0 to disable gamma correction.
const float FILTER_SCALE = 1.f; ///< Default filter scale value used in the Resampler() function. Filter scale - values < 1.0 cause aliasing, but create sharper looking mips.
-const char* const FILTER_TYPE = "lanczos4"; ///< Default filter used in the Resampler() function. Possible Lanczos filters are: lanczos3, lanczos4, lanczos6, lanczos12
+const Resampler::Filter FILTER_TYPE = Resampler::LANCZOS4; ///< Default filter used in the Resampler() function. Possible Lanczos filters are: lanczos3, lanczos4, lanczos6, lanczos12
using Integration::Bitmap;
using Integration::BitmapPtr;
*/
ImageDimensions CalculateDesiredDimensions( unsigned int bitmapWidth, unsigned int bitmapHeight, unsigned int requestedWidth, unsigned int requestedHeight )
{
+ unsigned int maxSize = Dali::GetMaxTextureSize();
+
// If no dimensions have been requested, default to the source ones:
if( requestedWidth == 0 && requestedHeight == 0 )
{
- return ImageDimensions( bitmapWidth, bitmapHeight );
+ return ImageDimensions( std::min( bitmapWidth, maxSize ), std::min( bitmapHeight, maxSize ) );
}
// If both dimensions have values requested, use them both:
if( requestedWidth != 0 && requestedHeight != 0 )
{
- return ImageDimensions( requestedWidth, requestedHeight );
+ return ImageDimensions( std::min( requestedWidth, maxSize ), std::min( requestedHeight, maxSize ) );
}
// Only one of the dimensions has been requested. Calculate the other from
// the requested one and the source image aspect ratio:
if( requestedWidth != 0 )
{
+ requestedWidth = std::min( requestedWidth, maxSize );
return ImageDimensions( requestedWidth, bitmapHeight / float(bitmapWidth) * requestedWidth + 0.5f );
}
+
+ requestedHeight = std::min( requestedHeight, maxSize );
return ImageDimensions( bitmapWidth / float(bitmapHeight) * requestedHeight + 0.5f, requestedHeight );
}
--- /dev/null
+/*
+ * Copyright (c) 2017 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 "pixel-manipulation.h"
+
+// INTERNAL HEADERS
+#include <dali/public-api/images/pixel.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+struct Location
+{
+ unsigned int bitShift;
+ unsigned int bitMask;
+ bool available;
+};
+
+struct Locations
+{
+ Location luminance;
+ Location alpha;
+ Location red;
+ Location green;
+ Location blue;
+};
+
+
+bool HasChannel( Dali::Pixel::Format pixelFormat, Channel channel )
+{
+ switch (pixelFormat)
+ {
+ case Dali::Pixel::A8:
+ {
+ return (channel == ALPHA);
+ }
+ case Dali::Pixel::L8:
+ {
+ return (channel == LUMINANCE);
+ }
+ case Dali::Pixel::LA88:
+ {
+ return ( channel == LUMINANCE || channel == ALPHA );
+ }
+ case Dali::Pixel::RGB565:
+ case Dali::Pixel::BGR565:
+ case Dali::Pixel::RGB888:
+ case Dali::Pixel::RGB8888:
+ case Dali::Pixel::BGR8888:
+ {
+ return ( channel == RED || channel == GREEN || channel == BLUE );
+ }
+
+ case Dali::Pixel::RGBA8888:
+ case Dali::Pixel::BGRA8888:
+ case Dali::Pixel::RGBA4444:
+ case Dali::Pixel::BGRA4444:
+ case Dali::Pixel::RGBA5551:
+ case Dali::Pixel::BGRA5551:
+ {
+ return ( channel == RED || channel == GREEN || channel == BLUE || channel == ALPHA );
+ }
+
+ case Dali::Pixel::INVALID:
+ case Dali::Pixel::COMPRESSED_R11_EAC:
+ case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
+ case Dali::Pixel::COMPRESSED_RG11_EAC:
+ case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
+ case Dali::Pixel::COMPRESSED_RGB8_ETC2:
+ case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
+ case Dali::Pixel::COMPRESSED_RGB8_ETC1:
+ case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
+ case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR:
+ case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+ case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+ {
+ DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple channels.\n");
+ break;
+ }
+ }
+
+ return false;
+}
+
+unsigned int ReadChannel( unsigned char* pixelData,
+ Dali::Pixel::Format pixelFormat,
+ Channel channel )
+{
+ switch (pixelFormat)
+ {
+ case Dali::Pixel::A8:
+ {
+ if( channel == ALPHA )
+ {
+ return static_cast<unsigned int>(*pixelData);
+ }
+ else return 0u;
+ }
+ case Dali::Pixel::L8:
+ {
+ if( channel == LUMINANCE )
+ {
+ return static_cast<unsigned int>(*pixelData);
+ }
+ else return 0u;
+ }
+ case Dali::Pixel::LA88:
+ {
+ if( channel == LUMINANCE )
+ {
+ return static_cast<unsigned int>(*pixelData);
+ }
+ else if( channel == ALPHA )
+ {
+ return static_cast<unsigned int>(*(pixelData+1));
+ }
+ else return 0u;
+ }
+ case Dali::Pixel::RGB565:
+ {
+ if( channel == RED )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+ }
+ else if( channel == GREEN )
+ {
+ return ((static_cast<unsigned int>(*pixelData) & 0x07) << 3) |
+ ((static_cast<unsigned int>(*(pixelData+1)) & 0xE0) >> 5);
+ }
+ else if( channel == BLUE )
+ {
+ return static_cast<unsigned int>(*(pixelData+1)) & 0x1F;
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::BGR565:
+ {
+ if( channel == BLUE )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+ }
+ else if( channel == GREEN )
+ {
+ return ((static_cast<unsigned int>(*pixelData) & 0x07) << 3) |
+ ((static_cast<unsigned int>(*(pixelData+1)) & 0xE0) >> 5);
+ }
+ else if( channel == RED )
+ {
+ return (static_cast<unsigned int>(*(pixelData+1) & 0x1F) );
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::RGB888:
+ case Dali::Pixel::RGB8888:
+ {
+ if( channel == RED )
+ {
+ return static_cast<unsigned int>(*pixelData);
+ }
+ else if( channel == GREEN )
+ {
+ return static_cast<unsigned int>(*(pixelData+1));
+ }
+ else if( channel == BLUE )
+ {
+ return static_cast<unsigned int>(*(pixelData+2));
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::BGR8888:
+ {
+ if( channel == BLUE )
+ {
+ return static_cast<unsigned int>(*pixelData);
+ }
+ else if( channel == GREEN )
+ {
+ return static_cast<unsigned int>(*(pixelData+1));
+ }
+ else if( channel == RED )
+ {
+ return static_cast<unsigned int>(*(pixelData+2));
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::RGBA8888:
+ {
+ if( channel == RED )
+ {
+ return static_cast<unsigned int>(*pixelData);
+ }
+ else if( channel == GREEN )
+ {
+ return static_cast<unsigned int>(*(pixelData+1));
+ }
+ else if( channel == BLUE )
+ {
+ return static_cast<unsigned int>(*(pixelData+2));
+ }
+ else if( channel == ALPHA )
+ {
+ return static_cast<unsigned int>(*(pixelData+3));
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::BGRA8888:
+ {
+ if( channel == BLUE )
+ {
+ return static_cast<unsigned int>(*pixelData);
+ }
+ else if( channel == GREEN )
+ {
+ return static_cast<unsigned int>(*(pixelData+1));
+ }
+ else if( channel == RED )
+ {
+ return static_cast<unsigned int>(*(pixelData+2));
+ }
+ else if( channel == ALPHA )
+ {
+ return static_cast<unsigned int>(*(pixelData+3));
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::RGBA4444:
+ {
+ if( channel == RED )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0xF0) >> 4;
+ }
+ else if( channel == GREEN )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0x0F);
+ }
+ else if( channel == BLUE )
+ {
+ return (static_cast<unsigned int>(*(pixelData+1)) & 0xF0) >> 4;
+ }
+ else if( channel == ALPHA )
+ {
+ return (static_cast<unsigned int>(*(pixelData+1)) & 0x0F);
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::BGRA4444:
+ {
+ if( channel == BLUE )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0xF0) >> 4;
+ }
+ else if( channel == GREEN )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0x0F);
+ }
+ else if( channel == RED )
+ {
+ return (static_cast<unsigned int>(*(pixelData+1)) & 0xF0) >> 4;
+ }
+ else if( channel == ALPHA )
+ {
+ return (static_cast<unsigned int>(*(pixelData+1)) & 0x0F);
+ }
+ else return 0u;
+ }
+
+ case Dali::Pixel::RGBA5551:
+ {
+ if( channel == RED )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+ }
+ else if( channel == GREEN )
+ {
+ return ((static_cast<unsigned int>(*pixelData) & 0x07) << 2) |
+ ((static_cast<unsigned int>(*(pixelData+1)) & 0xC0) >> 6);
+ }
+ else if( channel == BLUE )
+ {
+ return (static_cast<unsigned int>(*(pixelData+1)) & 0x3E) >> 1;
+ }
+ else if( channel == ALPHA )
+ {
+ return static_cast<unsigned int>(*(pixelData+1)) & 0x01;
+ }
+
+ else return 0u;
+ }
+
+ case Dali::Pixel::BGRA5551:
+ {
+ if( channel == BLUE )
+ {
+ return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+ }
+ else if( channel == GREEN )
+ {
+ return ((static_cast<unsigned int>(*pixelData) & 0x07) << 2) |
+ ((static_cast<unsigned int>(*(pixelData+1)) & 0xC0) >> 6);
+ }
+ else if( channel == RED )
+ {
+ return ( static_cast<unsigned int>(*(pixelData+1)) & 0x3E) >> 1;
+ }
+ else if( channel == ALPHA )
+ {
+ return static_cast<unsigned int>(*(pixelData+1)) & 0x01;
+ }
+
+ else return 0u;
+ }
+
+ default:
+ {
+ return 0u;
+ }
+ }
+}
+
+void WriteChannel( unsigned char* pixelData,
+ Dali::Pixel::Format pixelFormat,
+ Channel channel,
+ unsigned int channelValue )
+{
+ switch (pixelFormat)
+ {
+ case Dali::Pixel::A8:
+ {
+ if( channel == ALPHA )
+ {
+ *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ break;
+ }
+ case Dali::Pixel::L8:
+ {
+ if( channel == LUMINANCE )
+ {
+ *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ break;
+ }
+ case Dali::Pixel::LA88:
+ {
+ if( channel == LUMINANCE )
+ {
+ *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == ALPHA )
+ {
+ *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ break;
+ }
+ case Dali::Pixel::RGB565:
+ {
+ if( channel == RED )
+ {
+ *pixelData &= ~0xF8;
+ *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+ }
+ else if( channel == GREEN )
+ {
+ *pixelData &= ~0x07;
+ *pixelData |= static_cast<unsigned char>( (channelValue >> 3) & 0x07 );
+
+ *(pixelData+1) &= ~0xE0;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 5) & 0xE0 );
+ }
+ else if( channel == BLUE )
+ {
+ *(pixelData+1) &= ~0x1F;
+ *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x1F );
+ }
+ break;
+ }
+
+ case Dali::Pixel::BGR565:
+ {
+ if( channel == BLUE )
+ {
+ *pixelData &= ~0xF8;
+ *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+ }
+ else if( channel == GREEN )
+ {
+ *pixelData &= ~0x07;
+ *pixelData |= static_cast<unsigned char>( (channelValue >> 3) & 0x07 );
+
+ *(pixelData+1) &= ~0xE0;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 5) & 0xE0 );
+ }
+ else if( channel == RED )
+ {
+ *(pixelData+1) &= ~0x1F;
+ *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x1F );
+ }
+ break;
+ }
+
+ case Dali::Pixel::RGB888:
+ case Dali::Pixel::RGB8888:
+ {
+ if( channel == RED )
+ {
+ *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == GREEN )
+ {
+ *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == BLUE )
+ {
+ *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ break;
+ }
+
+ case Dali::Pixel::BGR8888:
+ {
+ if( channel == BLUE )
+ {
+ *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == GREEN )
+ {
+ *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == RED )
+ {
+ *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ break;
+ }
+
+ case Dali::Pixel::RGBA8888:
+ {
+ if( channel == RED )
+ {
+ *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == GREEN )
+ {
+ *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == BLUE )
+ {
+ *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == ALPHA )
+ {
+ *(pixelData+3) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ break;
+ }
+
+ case Dali::Pixel::BGRA8888:
+ {
+ if( channel == BLUE )
+ {
+ *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == GREEN )
+ {
+ *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == RED )
+ {
+ *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ else if( channel == ALPHA )
+ {
+ *(pixelData+3) = static_cast<unsigned char>( channelValue & 0xFF );
+ }
+ break;
+ }
+
+ case Dali::Pixel::RGBA4444:
+ {
+ if( channel == RED )
+ {
+ *pixelData &= ~0xF0;
+ *pixelData |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+ }
+ else if( channel == GREEN )
+ {
+ *pixelData &= ~0x0F;
+ *pixelData |= static_cast<unsigned char>( channelValue & 0x0F );
+ }
+ else if( channel == BLUE )
+ {
+ *(pixelData+1) &= ~0xF0;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+ }
+ else if( channel == ALPHA )
+ {
+ *(pixelData+1) &= ~0x0F;
+ *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x0F );
+ }
+ break;
+ }
+
+ case Dali::Pixel::BGRA4444:
+ {
+ if( channel == BLUE )
+ {
+ *pixelData &= ~0xF0;
+ *pixelData |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+ }
+ else if( channel == GREEN )
+ {
+ *pixelData &= ~0x0F;
+ *pixelData |= static_cast<unsigned char>( channelValue & 0x0F );
+ }
+ else if( channel == RED )
+ {
+ *(pixelData+1) &= ~0xF0;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+ }
+ else if( channel == ALPHA )
+ {
+ *(pixelData+1) &= ~0x0F;
+ *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x0F );
+ }
+ break;
+ }
+
+ case Dali::Pixel::RGBA5551:
+ {
+ // rrrrrggg ggbbbbba
+ // F8 7 C0 3E 1
+ if( channel == RED )
+ {
+ *pixelData &= ~0xF8;
+ *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+ }
+ else if( channel == GREEN )
+ {
+ *pixelData &= ~0x07;
+ *pixelData |= static_cast<unsigned char>( (channelValue >> 2) & 0x07 );
+
+ *(pixelData+1) &= ~0xC0;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 6) & 0xC0 );
+ }
+ else if( channel == BLUE )
+ {
+ *(pixelData+1) &= ~0x3E;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 1) & 0x3E );
+ }
+ else if( channel == ALPHA )
+ {
+ *(pixelData+1) &= ~0x01;
+ *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x01 );
+ }
+ break;
+ }
+
+ case Dali::Pixel::BGRA5551:
+ {
+ if( channel == BLUE )
+ {
+ *pixelData &= ~0xF8;
+ *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+ }
+ else if( channel == GREEN )
+ {
+ *pixelData &= ~0x07;
+ *pixelData |= static_cast<unsigned char>( (channelValue >> 2) & 0x07 );
+
+ *(pixelData+1) &= ~0xC0;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 6) & 0xC0 );
+ }
+ else if( channel == RED )
+ {
+ *(pixelData+1) &= ~0x3E;
+ *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 1 ) & 0x3E );
+ }
+ else if( channel == ALPHA )
+ {
+ *(pixelData+1) &= ~0x01;
+ *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x01 );
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void ConvertColorChannelsToRGBA8888(
+ unsigned char* srcPixel, int srcOffset, Dali::Pixel::Format srcFormat,
+ unsigned char* destPixel, int destOffset )
+{
+ int red = ReadChannel(srcPixel+srcOffset, srcFormat, RED );
+ int green = ReadChannel(srcPixel+srcOffset, srcFormat, GREEN );
+ int blue = ReadChannel(srcPixel+srcOffset, srcFormat, BLUE );
+ switch( srcFormat )
+ {
+ case Dali::Pixel::RGB565:
+ case Dali::Pixel::BGR565:
+ {
+ red = (red<<3) | (red & 0x07);
+ green = (green << 2) | (green & 0x03);
+ blue = (blue<<3) | (blue & 0x07);
+ break;
+ }
+ case Dali::Pixel::RGBA4444:
+ case Dali::Pixel::BGRA4444:
+ {
+ red = (red<<4) | (red&0x0F);
+ green = (green<<4) | (green&0x0F);
+ blue = (blue<<4) | (blue&0x0F);
+ break;
+ }
+ case Dali::Pixel::RGBA5551:
+ case Dali::Pixel::BGRA5551:
+ {
+ red = (red<<3) | (red&0x07);
+ green = (green<<3) | (green&0x07);
+ blue = (blue<<3) | (blue&0x07);
+ break;
+ }
+ default:
+ break;
+ }
+ WriteChannel(destPixel+destOffset, Dali::Pixel::RGBA8888, RED, red);
+ WriteChannel(destPixel+destOffset, Dali::Pixel::RGBA8888, GREEN, green);
+ WriteChannel(destPixel+destOffset, Dali::Pixel::RGBA8888, BLUE, blue);
+}
+
+
+int ConvertAlphaChannelToA8( unsigned char* srcPixel, int srcOffset, Dali::Pixel::Format srcFormat )
+{
+ int alpha = ReadChannel(srcPixel+srcOffset, srcFormat, ALPHA );
+ int destAlpha = alpha;
+ switch( srcFormat )
+ {
+ case Pixel::RGBA5551:
+ case Pixel::BGRA5551:
+ {
+ destAlpha = (alpha==0)?0:255;
+ break;
+ }
+ case Pixel::RGBA4444:
+ case Pixel::BGRA4444:
+ {
+ destAlpha = (alpha<<4) | (alpha&0x0F);
+ break;
+ }
+ default:
+ break;
+ }
+ return destAlpha;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
--- /dev/null
+#ifndef DALI_INTERNAL_ADAPTOR_PIXEL_MANIPULATION_H
+#define DALI_INTERNAL_ADAPTOR_PIXEL_MANIPULATION_H
+
+/*
+ * Copyright (c) 2017 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/public-api/images/pixel.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+enum Channel
+{
+ LUMINANCE,
+ RED,
+ GREEN,
+ BLUE,
+ ALPHA,
+ MAX_NUMBER_OF_CHANNELS
+};
+
+/**
+ * Return true if the channel exists in the pixel format
+ * @param[in] pixelFormat The pixelFormat
+ * @param[in] channel The channel to test for
+ * @return true if the channel exists
+ */
+bool HasChannel( Dali::Pixel::Format pixelFormat, Channel channel );
+
+
+/**
+ * Read a colour channel from the pixel with the given pixel format.
+ * Returns zero if the format does not support the channel
+ * @param[in] pixelData Location of the pixel
+ * @param[in] pixelFormat The format of the pixel
+ * @param[in] channel The channel to read
+ * @return the channel value
+ */
+unsigned int ReadChannel( unsigned char* pixelData,
+ Dali::Pixel::Format pixelFormat,
+ Channel channel );
+
+/**
+ * Write a colour channel to the pixel with the given pixel format.
+ * @param[in] pixelData Location of the pixel
+ * @param[in] pixelFormat The format of the pixel
+ * @param[in] channel The channel to write
+ * @param[in] channelValue the value to write to the channel
+ */
+void WriteChannel( unsigned char* pixelData,
+ Dali::Pixel::Format pixelFormat,
+ Channel channel,
+ unsigned int channelValue );
+
+/**
+ * Convert the colors in the source pixel from their natural format to RGBA8888.
+ * @param[in] srcBuffer The source buffer to read from
+ * @param[in] srcOffset The offset of the pixel to convert
+ * @param[in] srcFormat The pixel format of the source pixel
+ * @param[in] destBuffer The destination buffer to write to
+ * @param[in] destOffset The offset of the pixel to write
+ */
+void ConvertColorChannelsToRGBA8888(
+ unsigned char* srcBuffer, int srcOffset, Dali::Pixel::Format srcFormat,
+ unsigned char* destBuffer, int destOffset );
+
+/**
+ * Convert the alpha in the source pixel to A8.
+ * @param[in] srcBuffer The source buffer to read from
+ * @param[in] srcOffset The offset of the pixel to convert
+ * @param[in] srcFormat The pixel format of the source pixel
+ * @return the alpha value in the range 0-255
+ */
+int ConvertAlphaChannelToA8( unsigned char* srcPixel, int srcOffset, Dali::Pixel::Format srcFormat );
+
+
+} // Adaptor
+} // Internal
+} // Dali
+
+
+#endif // DALI_INTERNAL_ADAPTOR_PIXEL_MANIPULATION_H
$(tizen_platform_abstraction_src_dir)/image-loaders/loader-png.cpp \
$(tizen_platform_abstraction_src_dir)/image-loaders/loader-wbmp.cpp \
$(tizen_platform_abstraction_src_dir)/image-loaders/image-loader.cpp \
- $(portable_platform_abstraction_src_dir)/image-operations.cpp
+ \
+ $(portable_platform_abstraction_src_dir)/image-operations.cpp \
+ $(portable_platform_abstraction_src_dir)/pixel-manipulation.cpp \
+ $(portable_platform_abstraction_src_dir)/alpha-mask.cpp
# Add public headers here:
{
DaliFeedback::DaliFeedback()
-: mHapticInitialized( false )
{
feedback_initialize();
-
- if( 0 == haptic_open( HAPTIC_DEVICE_0, &mDeviceHandle ) )
- {
- mHapticInitialized = true;
- }
- else
- {
- DEBUG_PRINTF( "Haptic feedback controller failed to initialize\n" );
- }
}
DaliFeedback::~DaliFeedback()
{
- if( mHapticInitialized )
- {
- int errorCode = haptic_close( mDeviceHandle );
- if( errorCode < 0 )
- {
- DEBUG_PRINTF( "device_haptic_close() failed with error code: %d\n", errorCode );
- }
- }
-
feedback_deinitialize();
}
void DaliFeedback::PlayHaptic( const std::string& filePath )
{
- if( mHapticInitialized )
- {
- if ( filePath.size() == 0 )
- {
- DEBUG_PRINTF( "File Path can't be NULL!\n" );
- return;
- }
-
- int errorCode = haptic_vibrate_file_with_detail( mDeviceHandle, filePath.c_str(), HAPTIC_ITERATION_ONCE, HAPTIC_FEEDBACK_AUTO, HAPTIC_PRIORITY_MIN, NULL );
- if( errorCode != 0 )
- {
- DEBUG_PRINTF( "PlayHaptic() failed with error code: %d\n", errorCode );
- }
- }
- else
- {
- DEBUG_PRINTF( "HapticPlayer is not Initialized\n" );
- }
}
void DaliFeedback::PlayHapticMonotone( unsigned int duration )
{
- if( mHapticInitialized )
- {
- int errorCode = haptic_vibrate_monotone_with_detail( mDeviceHandle, duration, HAPTIC_FEEDBACK_AUTO, HAPTIC_PRIORITY_MIN, NULL );
- if( errorCode != 0 )
- {
- DEBUG_PRINTF( "PlayHapticMonotone() failed with error code: %d\n", errorCode );
- }
- }
- else
- {
- DEBUG_PRINTF( "HapticPlayer is not Initialized\n" );
- }
}
void DaliFeedback::StopHaptic()
{
- if( mHapticInitialized )
- {
- int errorCode = haptic_stop_all_effects( mDeviceHandle );
- if( errorCode != 0 )
- {
- DEBUG_PRINTF( "StopHaptic() failed with error code: %d\n", errorCode );
- }
- }
- else
- {
- DEBUG_PRINTF( "HapticPlayer is not Initialized\n" );
- }
}
int DaliFeedback::PlaySound( const std::string& fileName )
*
*/
-// EXTERNAL INCLUDES
-#if defined(DALI_PROFILE_MOBILE)
-#include <dd-haptic.h>
-#else
-#include <haptic.h>
-#endif
-
// INTERNAL INCLUDES
#include <feedback-plugin.h>
* @copydoc Dali::FeedbackPlugin::PlayFeedbackPattern()
*/
void PlayFeedbackPattern( int type, int pattern );
-
-private:
-
- haptic_device_h mDeviceHandle;
-
- bool mHapticInitialized;
};
} // namespace Plugin
mPlayerState( PLAYER_STATE_NONE ),
mTbmSurface( NULL ),
mPacket( NULL ),
- mBackgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
- mTargetType( NativeImage )
+ mTargetType( NativeImage ),
+ mAlphaBitChanged( false )
{
}
}
mNativeImageSourcePtr = NULL;
+ mEcoreWlWindow = NULL;
if( target.GetType() == typeid( Dali::NativeImageSourcePtr ) )
{
- if( mTargetType == TizenVideoPlayer::WindowSurface )
- {
- Stage::GetCurrent().SetBackgroundColor( mBackgroundColor );
- }
mTargetType = TizenVideoPlayer::NativeImage;
Dali::NativeImageSourcePtr nativeImageSourcePtr = AnyCast< Dali::NativeImageSourcePtr >( target );
else if( target.GetType() == typeid( Ecore_Wl_Window* ) )
{
mTargetType = TizenVideoPlayer::WindowSurface;
- mBackgroundColor = Stage::GetCurrent().GetBackgroundColor();
- Stage::GetCurrent().SetBackgroundColor( Color::TRANSPARENT );
Ecore_Wl_Window* nativeWindow = Dali::AnyCast< Ecore_Wl_Window* >( target );
InitializeUnderlayMode( nativeWindow );
mNativeImageSourcePtr = nativeImageSourcePtr;
+ if( mAlphaBitChanged )
+ {
+ ecore_wl_window_alpha_set( mEcoreWlWindow, false );
+ mAlphaBitChanged = false;
+ }
+
if( mPlayerState == PLAYER_STATE_NONE )
{
error = player_create( &mPlayer );
}
GetPlayerState( &mPlayerState );
+ mEcoreWlWindow = ecoreWlWindow;
if( mPlayerState == PLAYER_STATE_IDLE )
{
error = player_set_sound_type( mPlayer, SOUND_TYPE_MEDIA );
LogPlayerError( error );
- error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_FULL_SCREEN );
+ error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_DST_ROI );
LogPlayerError( error );
+ error = player_set_display_roi_area( mPlayer, 0, 0, 1, 1 );
+
int width, height;
+ mAlphaBitChanged = ( ecore_wl_window_alpha_get( mEcoreWlWindow ) )? false: true;
ecore_wl_screen_size_get( &width, &height );
- error = player_set_ecore_wl_display( mPlayer, PLAYER_DISPLAY_TYPE_OVERLAY, ecoreWlWindow, 0, 0, width, height );
+
+ if( mAlphaBitChanged )
+ {
+ ecore_wl_window_alpha_set( mEcoreWlWindow, true );
+ }
+ error = player_set_ecore_wl_display( mPlayer, PLAYER_DISPLAY_TYPE_OVERLAY, mEcoreWlWindow, 0, 0, width, height );
LogPlayerError( error );
error = player_set_display_visible( mPlayer, true );
mPacketVector.PushBack( packet );
}
+void TizenVideoPlayer::SetDisplayArea( DisplayArea area )
+{
+ GetPlayerState( &mPlayerState );
+
+ if( mNativeImageSourcePtr != NULL )
+ {
+ DALI_LOG_ERROR( "SetDisplayArea is only for window surface target.\n" );
+ return;
+ }
+
+ if( mPlayerState == PLAYER_STATE_IDLE ||
+ mPlayerState == PLAYER_STATE_READY ||
+ mPlayerState == PLAYER_STATE_PLAYING ||
+ mPlayerState == PLAYER_STATE_PAUSED
+
+ )
+ {
+ int error = player_set_display_roi_area( mPlayer, area.x, area.y, area.width, area.height );
+ LogPlayerError( error );
+ }
+}
+
+void TizenVideoPlayer::Forward( int millisecond )
+{
+ int error;
+
+ GetPlayerState( &mPlayerState );
+
+ if( mPlayerState == PLAYER_STATE_READY ||
+ mPlayerState == PLAYER_STATE_PLAYING ||
+ mPlayerState == PLAYER_STATE_PAUSED
+ )
+ {
+ int currentPosition = 0;
+ int nextPosition = 0;
+
+ error = player_get_play_position( mPlayer, ¤tPosition );
+ LogPlayerError( error );
+
+ nextPosition = currentPosition + millisecond;
+
+ error = player_set_play_position( mPlayer, nextPosition, true, NULL, NULL );
+ LogPlayerError( error );
+ }
+}
+
+void TizenVideoPlayer::Backward( int millisecond )
+{
+ int error;
+
+ GetPlayerState( &mPlayerState );
+
+ if( mPlayerState == PLAYER_STATE_READY ||
+ mPlayerState == PLAYER_STATE_PLAYING ||
+ mPlayerState == PLAYER_STATE_PAUSED
+ )
+ {
+ int currentPosition = 0;
+ int nextPosition = 0;
+
+ error = player_get_play_position( mPlayer, ¤tPosition );
+ LogPlayerError( error );
+
+ nextPosition = currentPosition - millisecond;
+ nextPosition = ( nextPosition < 0 )? 0 : nextPosition;
+
+ error = player_set_play_position( mPlayer, nextPosition, true, NULL, NULL );
+ LogPlayerError( error );
+ }
+}
+
} // namespace Plugin
} // namespace Dali;
virtual int GetPlayPosition();
/**
+ * @copydoc Dali::VideoPlayerPlugin::SetDisplayArea()
+ */
+ virtual void SetDisplayArea( DisplayArea area );
+
+ /**
* @copydoc Dali::VideoPlayerPlugin::SetDisplayRotation()
*/
virtual void SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation );
*/
void PushPacket( media_packet_h packet );
+ /**
+ * @brief Dali::VideoPlayer::Forward()
+ */
+ void Forward( int millisecond );
+
+ /**
+ * @brief Dali::VideoPlayer::Backward()
+ */
+ void Backward( int millisecond );
+
private:
/**
Dali::Mutex mPacketMutex;
Dali::Vector< media_packet_h > mPacketVector; ///< Container for media packet handle from Tizen player callback
+ Ecore_Wl_Window* mEcoreWlWindow;
+
+ bool mAlphaBitChanged; ///< True if underlay rendering initialization changes window alpha
+
public:
Dali::VideoPlayerPlugin::VideoPlayerSignalType mFinishedSignal;
// Ol Chiki Script
// 0x1c50 - 0x1c7f Ol Chiki
+ // Meitei Script
+ // 0xabc0 - 0xabff Meetei Mayek
+ // 0xaae0 - 0xaaff Meetei Mayek Extensions
+
// The Emoji which map to standardized Unicode characters
// 1. Emoticons ( 1F601 - 1F64F )
// 2. Dingbats ( 2702 - 27B0 )
{
return LATIN;
}
+ if( ( 0xaae0 <= character ) && ( character <= 0xaaff ) )
+ {
+ return MEITEI;
+ }
+ if( ( 0xabc0 <= character ) && ( character <= 0xabff ) )
+ {
+ return MEITEI;
+ }
if( ( 0xac00 <= character ) && ( character <= 0xd7af ) )
{
return HANGUL;
GEEZ, ///< The Ge'ez script. Used by the Amharic, Tigrinya and other languages in Ethiopia and Eritrea.
OL_CHIKI, ///< The Ol Chiki script. Used by the Santali.
BAYBAYIN, ///< The Baybayin script. Used by the Tagalog, Bikol languages, Ilocano, Pangasinan, Visayan and other languages in Philippines.
+ MEITEI, ///< The Meitei script used for the Meitei language in Manipur, India.
EMOJI, ///< The Emoji which map to standardized Unicode characters.
"GEEZ", ///< The Ge'ez script also known as Ethiopic. Used by the Amharic, Tigrinya and other languages in Ethiopia and Eritrea.
"OL_CHIKI", ///< The Ol Chiki script. Used by the Santali.
"BAYBAYIN", ///< The Baybayin script. Used by the Tagalog, Bikol languages, Ilocano, Pangasinan, Visayan and other languages in Philippines.
+ "MEITEI", ///< The Meitei script used for the Meitei language in Manipur, India.
"EMOJI", ///< The Emoji which map to standardized Unicode characters.
HB_SCRIPT_ETHIOPIC,
HB_SCRIPT_OL_CHIKI,
HB_SCRIPT_TAGALOG,
+ HB_SCRIPT_MEETEI_MAYEK,
HB_SCRIPT_UNKNOWN, // EMOJI
HB_SCRIPT_UNKNOWN, // SYMBOLS1
// filters[] is a list of all the available filter functions.
static struct
{
- char name[32];
+ Resampler::Filter name;
Resample_Real (*func)(Resample_Real t);
Resample_Real support;
} g_filters[] =
{
- { "box", box_filter, BOX_FILTER_SUPPORT },
- { "tent", tent_filter, TENT_FILTER_SUPPORT },
- { "bell", bell_filter, BELL_SUPPORT },
- { "b-spline", B_spline_filter, B_SPLINE_SUPPORT },
- { "mitchell", mitchell_filter, MITCHELL_SUPPORT },
- { "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT },
- { "blackman", blackman_filter, BLACKMAN_SUPPORT },
- { "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT },
- { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT },
- { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT },
- { "kaiser", kaiser_filter, KAISER_SUPPORT },
- { "gaussian", gaussian_filter, GAUSSIAN_SUPPORT },
- { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT },
- { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT },
- { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT },
- { "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT },
+ { Resampler::BOX, box_filter, BOX_FILTER_SUPPORT },
+ { Resampler::TENT, tent_filter, TENT_FILTER_SUPPORT },
+ { Resampler::BELL, bell_filter, BELL_SUPPORT },
+ { Resampler::B_SPLINE, B_spline_filter, B_SPLINE_SUPPORT },
+ { Resampler::MITCHELL, mitchell_filter, MITCHELL_SUPPORT },
+ { Resampler::LANCZOS3, lanczos3_filter, LANCZOS3_SUPPORT },
+ { Resampler::BLACKMAN, blackman_filter, BLACKMAN_SUPPORT },
+ { Resampler::LANCZOS4, lanczos4_filter, LANCZOS4_SUPPORT },
+ { Resampler::LANCZOS6, lanczos6_filter, LANCZOS6_SUPPORT },
+ { Resampler::LANCZOS12, lanczos12_filter, LANCZOS12_SUPPORT },
+ { Resampler::KAISER, kaiser_filter, KAISER_SUPPORT },
+ { Resampler::GAUSSIAN, gaussian_filter, GAUSSIAN_SUPPORT },
+ { Resampler::CATMULLROM, catmull_rom_filter, CATMULL_ROM_SUPPORT },
+ { Resampler::QUADRATIC_INTERPOLATION, quadratic_interp_filter, QUADRATIC_SUPPORT },
+ { Resampler::QUADRATIC_APPROXIMATION, quadratic_approx_filter, QUADRATIC_SUPPORT },
+ { Resampler::QUADRATIC_MIX, quadratic_mix_filter, QUADRATIC_SUPPORT },
};
static const int NUM_FILTERS = sizeof(g_filters) / sizeof(g_filters[0]);
int dst_x, int dst_y,
Boundary_Op boundary_op,
Resample_Real sample_low, Resample_Real sample_high,
- const char* Pfilter_name,
+ Resampler::Filter filter,
Contrib_List* Pclist_x,
Contrib_List* Pclist_y,
Resample_Real filter_x_scale,
}
// Find the specified filter.
-
- if (Pfilter_name == NULL)
- Pfilter_name = RESAMPLER_DEFAULT_FILTER;
-
for (i = 0; i < NUM_FILTERS; i++)
- if (strcmp(Pfilter_name, g_filters[i].name) == 0)
+ if ( filter == g_filters[i].name )
break;
if (i == NUM_FILTERS)
{
- m_status = STATUS_BAD_FILTER_NAME;
+ m_status = STATUS_BAD_FILTER_TYPE;
return;
}
*ptr_clist_y = m_Pclist_y;
}
-int Resampler::get_filter_num()
-{
- return NUM_FILTERS;
-}
-
-char* Resampler::get_filter_name(int filter_num)
-{
- if ((filter_num < 0) || (filter_num >= NUM_FILTERS))
- return NULL;
- else
- return g_filters[filter_num].name;
-}
-
#pragma GCC diagnostic pop
// resampler.h, Separable filtering image rescaler v2.21, Rich Geldreich - richgel99@gmail.com
// See unlicense.org text at the bottom of this file.
+// Modified to specify filters as enum rather than char *
#ifndef __RESAMPLER_H__
#define __RESAMPLER_H__
#define RESAMPLER_DEBUG_OPS 0
-#define RESAMPLER_DEFAULT_FILTER "lanczos4"
#define RESAMPLER_MAX_DIMENSION 16384
public:
typedef Resample_Real Sample;
+ /**
+ * Supported filter types
+ */
+ enum Filter
+ {
+ BOX,
+ TENT,
+ BELL,
+ B_SPLINE,
+ MITCHELL,
+ LANCZOS3,
+ BLACKMAN,
+ LANCZOS4,
+ LANCZOS6,
+ LANCZOS12,
+ KAISER,
+ GAUSSIAN,
+ CATMULLROM,
+ QUADRATIC_INTERPOLATION,
+ QUADRATIC_APPROXIMATION,
+ QUADRATIC_MIX,
+ };
+
struct Contrib
{
Resample_Real weight;
{
STATUS_OKAY = 0,
STATUS_OUT_OF_MEMORY = 1,
- STATUS_BAD_FILTER_NAME = 2,
+ STATUS_BAD_FILTER_TYPE = 2,
STATUS_SCAN_BUFFER_FULL = 3
};
int dst_x, int dst_y,
Boundary_Op boundary_op = BOUNDARY_CLAMP,
Resample_Real sample_low = 0.0f, Resample_Real sample_high = 0.0f,
- const char* Pfilter_name = RESAMPLER_DEFAULT_FILTER,
+ Resampler::Filter = Resampler::LANCZOS3,
Contrib_List* Pclist_x = NULL,
Contrib_List* Pclist_y = NULL,
Resample_Real filter_x_scale = 1.0f,
Contrib_List* get_clist_x() const { return m_Pclist_x; }
Contrib_List* get_clist_y() const { return m_Pclist_y; }
- // Filter accessors.
- static int get_filter_num();
- static char* get_filter_name(int filter_num);
-
private:
Resampler();
Resampler(const Resampler& o);