}
DisplayConnection::DisplayConnection()
+: mImpl( NULL )
{
}
mPanMinimumEvents( -1 ),
mGlesCallTime( 0 ),
mWindowWidth( 0 ),
- mWindowHeight( 0 )
+ mWindowHeight( 0 ),
+ mLogFunction( NULL )
{
ParseEnvironmentOptions();
}
// EXTERNAL INCLUDES
#include <stdint.h>
-#include <dali/devel-api/common/mutex.h>
+#include <dali/devel-api/threading/mutex.h>
namespace Dali
{
// EXTERNAL INCLUDES
#include <pthread.h>
-#include <dali/devel-api/common/mutex.h>
+#include <dali/devel-api/threading/mutex.h>
#include <dali/public-api/common/dali-vector.h>
// INTERNAL INCLUDES
// EXTERNAL INCLDUES
#include <dali/public-api/common/dali-vector.h>
-#include <dali/devel-api/common/mutex.h>
+#include <dali/devel-api/threading/mutex.h>
// INTERNAL INCLUDES
#include <base/performance-logging/frame-time-stats.h>
*/
// EXTERNAL INCLUDES
-#include <dali/devel-api/common/mutex.h>
+#include <dali/devel-api/threading/mutex.h>
// INTERNAL INCLUDES
#include <base/performance-logging/performance-marker.h>
mThreadController(NULL),
mVSyncMonitor(NULL),
mGLES( NULL ),
+ mGlSync( NULL ),
mEglFactory( NULL ),
mNativeWindow( nativeWindow ),
mSurface( surface ),
mNotificationOnIdleInstalled( false ),
mNotificationTrigger(NULL),
mGestureManager(NULL),
+ mDaliFeedbackPlugin( NULL ),
+ mFeedbackController( NULL ),
mObservers(),
mDragAndDropDetector(),
mDeferredRotationObserver(NULL),
{
GlExtensions::GlExtensions()
- : mInitialized( false )
+ :
+#if DALI_GLES_VERSION < 30
+
+#ifdef GL_EXT_discard_framebuffer
+ mGlDiscardFramebuffer( NULL ),
+#endif
+#ifdef GL_OES_get_program_binary
+ mGlGetProgramBinaryOES( NULL ),
+ mGlProgramBinaryOES( NULL ),
+#endif
+
+#endif // DALI_GLES_VERSION < 30
+ mInitialized( false )
{
}
{
if( mOrientation == Dali::Window::LANDSCAPE
|| mOrientation == Dali::Window::LANDSCAPE_INVERSE
- || (mVisible != Dali::Window::VISIBLE) )
+ || (mVisible == Dali::Window::INVISIBLE)
+ || (mVisible == Dali::Window::AUTO && !mIsShowing) )
{
return false;
}
* Applications should follow the example below:
*
* @code
- * void CreateProgram(Application app)
+ * class ExampleController: public ConnectionTracker
* {
- * // Create Dali components...
- * // Can instantiate here, if required
- * }
+ * public:
+ * ExampleController( Application& application )
+ * : mApplication( application )
+ * {
+ * mApplication.InitSignal().Connect( this, &ExampleController::Create );
+ * }
+ *
+ * void Create( Application& application )
+ * {
+ * // Create Dali components...
+ * }
+ * ...
+ * private:
+ * Application& mApplication;
+ * };
*
* int main (int argc, char **argv)
* {
* Application app = Application::New(&argc, &argv);
- * app.InitSignal().Connect(&CreateProgram);
+ * ExampleController example( app );
* app.MainLoop();
* }
* @endcode
*
- * If required, you can also connect class member functions to a signal:
- *
- * @code
- * MyApplication app;
- * app.ResumeSignal().Connect(&app, &MyApplication::Resume);
- * @endcode
- *
* This class accepts command line arguments as well. The following options are supported:
*
* @code
*/
/**
- * @brief Enumerations for input method.
+ * @brief Enumerations for input method
* @since_tizen 2.4
*/
namespace InputMethod
*
* The 'Action' button is traditionally the [RETURN] or [DONE] button.
*
- * Not all these actions are supported by all systems
+ * Not all these actions are supported by all systems.
*
* Setting a custom label will still require one of these actions to be set.
* @since_tizen 2.4
*/
enum ActionButton
{
- ACTION_DEFAULT,
- ACTION_DONE,
- ACTION_GO,
- ACTION_JOIN,
- ACTION_LOGIN,
- ACTION_NEXT,
- ACTION_PREVIOUS,
- ACTION_SEARCH,
- ACTION_SEND,
- ACTION_SIGNIN,
- ACTION_UNSPECIFIED,
- ACTION_NONE
+ ACTION_DEFAULT, ///< Default action @since_tizen 2.4
+ ACTION_DONE, ///< Done @since_tizen 2.4
+ ACTION_GO, ///< Go action @since_tizen 2.4
+ ACTION_JOIN, ///< Join action @since_tizen 2.4
+ ACTION_LOGIN, ///< Login action @since_tizen 2.4
+ ACTION_NEXT, ///< Next action @since_tizen 2.4
+ ACTION_PREVIOUS, ///< Previous action @since_tizen 2.4
+ ACTION_SEARCH, ///< Search action @since_tizen 2.4
+ ACTION_SEND, ///< Send action @since_tizen 2.4
+ ACTION_SIGNIN, ///< Sign in action @since_tizen 2.4
+ ACTION_UNSPECIFIED, ///< Unspecified action @since_tizen 2.4
+ ACTION_NONE ///< Nothing to do @since_tizen 2.4
};
/**
* @brief Settings that can be changed in the system Input Method
*
- * Not all these settings are supported by all systems
+ * Not all these settings are supported by all systems.
* @since_tizen 2.4
*/
enum Settings
{
- ACTION_BUTTON, // ActionButton // Apply the one of the ActionButton functions to the action button (return button)
- AUTO_CAPITALISE, // boolean // Capitalise first letter of each sentence automatically
- AUTO_COMPLETE, // boolean // Suggest words based on the current input
- AUTO_CORRECT // boolean // Automatically correct commonly misspelt words
+ ACTION_BUTTON, ///< ActionButton. Apply the one of the ActionButton functions to the action button (return button). @since_tizen 2.4
+ AUTO_CAPITALISE, ///< boolean. Capitalise the first letter of each sentence automatically. @since_tizen 2.4
+ AUTO_COMPLETE, ///< boolean. Suggest words based on the current input. @since_tizen 2.4
+ AUTO_CORRECT ///< boolean. Automatically correct commonly misspelt words. @since_tizen 2.4
};
} // namespace InputMethod
enum KEY
{
- DALI_KEY_INVALID = -1,
- DALI_KEY_ESCAPE = 9,
- DALI_KEY_BACKSPACE = 22,
- DALI_KEY_SHIFT_LEFT = 50,
- DALI_KEY_SHIFT_RIGHT = 62,
- DALI_KEY_CURSOR_UP = 111,
- DALI_KEY_CURSOR_LEFT = 113,
- DALI_KEY_CURSOR_RIGHT = 114,
- DALI_KEY_CURSOR_DOWN = 116,
- DALI_KEY_BACK = 166,
- DALI_KEY_CAMERA = 167,
- DALI_KEY_CONFIG = 168,
- DALI_KEY_POWER = 169,
- DALI_KEY_PAUSE = 170,
- DALI_KEY_CANCEL = 171,
- DALI_KEY_PLAY_CD = 172,
- DALI_KEY_STOP_CD = 173,
- DALI_KEY_PAUSE_CD = 174,
- DALI_KEY_NEXT_SONG = 175,
- DALI_KEY_PREVIOUS_SONG = 176,
- DALI_KEY_REWIND = 177,
- DALI_KEY_FASTFORWARD = 178,
- DALI_KEY_MEDIA = 179,
- DALI_KEY_PLAY_PAUSE = 180,
- DALI_KEY_MUTE = 181,
- DALI_KEY_MENU = 182,
- DALI_KEY_HOME = 183,
- DALI_KEY_HOMEPAGE = 187,
- DALI_KEY_WEBPAGE = 188,
- DALI_KEY_MAIL = 189,
- DALI_KEY_SCREENSAVER = 190,
- DALI_KEY_BRIGHTNESS_UP = 191,
- DALI_KEY_BRIGHTNESS_DOWN = 192,
- DALI_KEY_SOFT_KBD = 193,
- DALI_KEY_QUICK_PANEL = 194,
- DALI_KEY_TASK_SWITCH = 195,
- DALI_KEY_APPS = 196,
- DALI_KEY_SEARCH = 197,
- DALI_KEY_VOICE = 198,
- DALI_KEY_LANGUAGE = 199,
- DALI_KEY_VOLUME_UP = 200,
- DALI_KEY_VOLUME_DOWN = 201
+ DALI_KEY_INVALID = -1, ///< Invalid key value @since_tizen 2.4
+ DALI_KEY_ESCAPE = 9, ///< Escape key @since_tizen 2.4
+ DALI_KEY_BACKSPACE = 22, ///< Backspace key @since_tizen 2.4
+ DALI_KEY_SHIFT_LEFT = 50, ///< Shift Left key @since_tizen 2.4
+ DALI_KEY_SHIFT_RIGHT = 62, ///< Shift Right key @since_tizen 2.4
+ DALI_KEY_CURSOR_UP = 111, ///< Cursor up key @since_tizen 2.4
+ DALI_KEY_CURSOR_LEFT = 113, ///< Cursor left key @since_tizen 2.4
+ DALI_KEY_CURSOR_RIGHT = 114, ///< Cursor right key @since_tizen 2.4
+ DALI_KEY_CURSOR_DOWN = 116, ///< Cursor down key @since_tizen 2.4
+ DALI_KEY_BACK = 166, ///< Back key @since_tizen 2.4
+ DALI_KEY_CAMERA = 167, ///< Camera key @since_tizen 2.4
+ DALI_KEY_CONFIG = 168, ///< Config key @since_tizen 2.4
+ DALI_KEY_POWER = 169, ///< Power key @since_tizen 2.4
+ DALI_KEY_PAUSE = 170, ///< Pause key @since_tizen 2.4
+ DALI_KEY_CANCEL = 171, ///< Cancel key @since_tizen 2.4
+ DALI_KEY_PLAY_CD = 172, ///< Play CD key @since_tizen 2.4
+ DALI_KEY_STOP_CD = 173, ///< Stop CD key @since_tizen 2.4
+ DALI_KEY_PAUSE_CD = 174, ///< Pause CD key @since_tizen 2.4
+ DALI_KEY_NEXT_SONG = 175, ///< Next song key @since_tizen 2.4
+ DALI_KEY_PREVIOUS_SONG = 176, ///< Previous song key @since_tizen 2.4
+ DALI_KEY_REWIND = 177, ///< Rewind key @since_tizen 2.4
+ DALI_KEY_FASTFORWARD = 178, ///< Fastforward key @since_tizen 2.4
+ DALI_KEY_MEDIA = 179, ///< Media key @since_tizen 2.4
+ DALI_KEY_PLAY_PAUSE = 180, ///< Play pause key @since_tizen 2.4
+ DALI_KEY_MUTE = 181, ///< Mute key @since_tizen 2.4
+ DALI_KEY_MENU = 182, ///< Menu key @since_tizen 2.4
+ DALI_KEY_HOME = 183, ///< Home key @since_tizen 2.4
+ DALI_KEY_HOMEPAGE = 187, ///< Homepage key @since_tizen 2.4
+ DALI_KEY_WEBPAGE = 188, ///< Webpage key @since_tizen 2.4
+ DALI_KEY_MAIL = 189, ///< Mail key @since_tizen 2.4
+ DALI_KEY_SCREENSAVER = 190, ///< Screensaver key @since_tizen 2.4
+ DALI_KEY_BRIGHTNESS_UP = 191, ///< Brightness up key @since_tizen 2.4
+ DALI_KEY_BRIGHTNESS_DOWN = 192, ///< Brightness down key @since_tizen 2.4
+ DALI_KEY_SOFT_KBD = 193, ///< Soft KBD key @since_tizen 2.4
+ DALI_KEY_QUICK_PANEL = 194, ///< Quick panel key @since_tizen 2.4
+ DALI_KEY_TASK_SWITCH = 195, ///< Task switch key @since_tizen 2.4
+ DALI_KEY_APPS = 196, ///< Apps key @since_tizen 2.4
+ DALI_KEY_SEARCH = 197, ///< Search key @since_tizen 2.4
+ DALI_KEY_VOICE = 198, ///< Voice key @since_tizen 2.4
+ DALI_KEY_LANGUAGE = 199, ///< Language key @since_tizen 2.4
+ DALI_KEY_VOLUME_UP = 200, ///< Volume up key @since_tizen 2.4
+ DALI_KEY_VOLUME_DOWN = 201 ///< Volume down key @since_tizen 2.4
};
/**
* @since_tizen 2.4
* @param keyEvent reference to a keyEvent structure
* @param daliKey dali key enum
- * @return true if the key is matched, false if not
+ * @return True if the key is matched, false if not
*/
-DALI_IMPORT_API bool IsKey( const KeyEvent& keyEvent, KEY daliKey);
+DALI_IMPORT_API bool IsKey( const Dali::KeyEvent& keyEvent, Dali::KEY daliKey);
/**
* @}
class NativeImageSource;
/**
- * @brief Pointer to Dali::NativeImageSource.
+ * @brief Pointer to Dali::NativeImageSource
* @since_tizen 2.4
*/
-typedef IntrusivePtr<NativeImageSource> NativeImageSourcePtr;
+typedef Dali::IntrusivePtr<Dali::NativeImageSource> NativeImageSourcePtr;
/**
* @brief Used for displaying native images.
*
* Depending on hardware the width and height may have to be a power of two.
* @since_tizen 2.4
- * @param[in] width The width of the image.
- * @param[in] height The height of the image.
+ * @param[in] width The width of the image
+ * @param[in] height The height of the image
* @param[in] depth color depth of the image
- * @return A smart-pointer to a newly allocated image.
+ * @return A smart-pointer to a newly allocated image
*/
static NativeImageSourcePtr New( unsigned int width, unsigned int height, ColorDepth depth );
*
* @since_tizen 2.4
* @param[in] nativeImageSource must be a X11 pixmap or a Ecore_X_Pixmap now.
- * @return A smart-pointer to a newly allocated image.
+ * @return A smart-pointer to a newly allocated image
*/
static NativeImageSourcePtr New( Any nativeImageSource );
* @brief Retrieve the internal native image.
*
* @since_tizen 2.4
- * @return Any object containing the internal native image.
+ * @return Any object containing the internal native image
*/
Any GetNativeImageSource();
* (COLOR_DEPTH_24 and COLOR_DEPTH_32).
* @since_tizen 2.4
* @param[out] pixbuf a vector to store the pixels in
- * @param[out] width width of image
- * @param[out] height height of image
+ * @param[out] width The width of image
+ * @param[out] height The height of image
* @param[out] pixelFormat pixel format used by image
* @return True if the pixels were gotten, and false otherwise.
*/
/**
* @brief Private constructor
* @since_tizen 2.4
- * @param[in] width The width of the image.
- * @param[in] height The height of the image.
+ * @param[in] width The width of the image
+ * @param[in] height The height of the image
* @param[in] depth color depth of the image
- * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+ * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty.
*/
DALI_INTERNAL NativeImageSource( unsigned int width, unsigned int height, ColorDepth depth, Any nativeImageSource );
*
* This avoids accidental calls to a default copy constructor.
* @since_tizen 2.4
- * @param[in] rhs A reference to the object to copy.
+ * @param[in] rhs A reference to the object to copy
*/
DALI_INTERNAL NativeImageSource( const NativeImageSource& nativeImageSource );
/**
- * @brief Undefined assignment operator.
+ * @brief Undefined assignment operator
*
* This avoids accidental calls to a default assignment operator.
* @since_tizen 2.4
- * @param[in] rhs A reference to the object to copy.
+ * @param[in] rhs A reference to the object to copy
*/
DALI_INTERNAL NativeImageSource& operator=(const NativeImageSource& rhs);
* @brief Signal emitted after specified time interval.
*
* The return of the callback decides whether signal emission stops or continues.
- * If the callback function returns false emission will stop, if true it will continue
+ * If the callback function returns false, emission will stop and if true, it will continue.
* This return value is ignored for one-shot events, which will always stop after the first execution.
* @returns The signal to Connect() with.
* @since_tizen 2.4
}
/**
- * @brief The Text-to-speech Player.
+ * @brief The Text-to-speech (TTS) Player.
* @since_tizen 2.4
*/
class DALI_IMPORT_API TtsPlayer : public BaseHandle
*/
enum IndicatorVisibleMode
{
- INVISIBLE = 0, ///< hide indicator @since_tizen 2.4
- VISIBLE = 1, ///< show indicator @since_tizen 2.4
- AUTO = 2 ///< hide in default, will show when necessary @since_tizen 2.4
+ INVISIBLE = 0, ///< Hide indicator @since_tizen 2.4
+ VISIBLE = 1, ///< Show indicator @since_tizen 2.4
+ AUTO = 2 ///< Hide in default, will show when necessary @since_tizen 2.4
};
// Methods
* @param[in] windowPosition The position and size of the window
* @param[in] name The window title
* @param[in] isTransparent Whether window is transparent
- * @return a new window
+ * @return A new window
*/
static Window New(PositionSize windowPosition, const std::string& name, bool isTransparent = false);
* @param[in] name The window title
* @param[in] className The window class name
* @param[in] isTransparent Whether window is transparent
- * @return a new window
+ * @return A new window
*/
static Window New(PositionSize windowPosition, const std::string& name, const std::string& className, bool isTransparent = false);
/**
* @brief This sets whether the indicator bar should be shown or not.
* @since_tizen 2.4
- * @param[in] visibleMode visible mode for indicator bar, VISIBLE in default
+ * @param[in] visibleMode Visible mode for indicator bar, VISIBLE in default
*/
void ShowIndicator( IndicatorVisibleMode visibleMode );
/**
* @brief This sets the opacity mode of indicator bar.
* @since_tizen 2.4
- * @param[in] opacity - The opacity mode
+ * @param[in] opacity The opacity mode
*/
void SetIndicatorBgOpacity( IndicatorBgOpacity opacity );
* @brief Set a preferred orientation.
* @since_tizen 2.4
* @param[in] orientation The preferred orientation
- * @pre orientation is in the list of available orientations
+ * @pre Orientation is in the list of available orientations
*/
void SetPreferredOrientation( WindowOrientation orientation );
* @param[in] window The window to set
* @param[in] dailKey The key code to ungrab (defined in key.h)
* @return true if the ungrab succeeds.
+ * @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 UngrabKeyTopmost( Window window, Dali::KEY daliKey );
* @param[in] window The window to set
* @param[in] dailKey The key code to ungrab (defined in key.h)
* @return true if the ungrab succeeds.
+ * @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 UngrabKey( Window window, Dali::KEY daliKey );
#include <dali/integration-api/gl-abstraction.h>
#include <dali/integration-api/debug.h>
-#include <dali/devel-api/common/mutex.h>
+#include <dali/devel-api/threading/mutex.h>
// INTERNAL INCLUDES
AC_SUBST(DALI_ADAPTOR_VERSION)
FREETYPE_REQUIRED=9.16.3
+FREETYPE_BITMAP_SUPPORT_VERSION=17.1.11
PKG_CHECK_MODULES(DALICORE, dali-core)
PKG_CHECK_MODULES(ELEMENTARY, elementary)
PKG_CHECK_MODULES(ECORE_IPC, ecore-ipc)
PKG_CHECK_MODULES(EXIF, libexif)
PKG_CHECK_MODULES(FREETYPE, [freetype2 >= $FREETYPE_REQUIRED])
+PKG_CHECK_MODULES(FREETYPE_BITMAP_SUPPORT, [freetype2 >= $FREETYPE_BITMAP_SUPPORT_VERSION], [ freetype_bitmap_support=yes ], [ freetype_bitmap_support=no ] )
PKG_CHECK_MODULES(FONTCONFIG, fontconfig)
PKG_CHECK_MODULES(PNG, libpng)
PKG_CHECK_MODULES(LIBEXIF, libexif)
])
fi
+if test "x$freetype_bitmap_support" = "xyes"; then
+DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DFREETYPE_BITMAP_SUPPORT"
+fi
+
AC_OUTPUT
Prefix: $prefix
Debug Build: $enable_debug
Compile flags $DALI_ADAPTOR_CFLAGS
+ Freetype bitmap support (Emoji): $freetype_bitmap_support
Profile: $enable_profile
Data Dir (Read/Write): $dataReadWriteDir
Data Dir (Read Only): $dataReadOnlyDir
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * 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.
namespace
{
+// The BORDER_FILL_VALUE is a single byte value that is used for horizontal and vertical borders.
+// A value of 0x00 gives us transparency for pixel buffers with an alpha channel, or black otherwise.
+// We can optionally use a Vector4 color here, but at reduced fill speed.
+const uint8_t BORDER_FILL_VALUE( 0x00 );
+// A maximum size limit for newly created bitmaps. ( 1u << 16 ) - 1 is chosen as we are using 16bit words for dimensions.
+const unsigned int MAXIMUM_TARGET_BITMAP_SIZE( ( 1u << 16 ) - 1 );
+
using Integration::Bitmap;
using Integration::BitmapPtr;
typedef unsigned char PixelBuffer;
}
/**
+ * @brief Calculate the number of lines on the X and Y axis that need to be
+ * either added or removed with repect to the specified fitting mode.
+ * (e.g., nearest or linear).
+ * @param[in] sourceSize The size of the source image
+ * @param[in] fittingMode The fitting mode to use
+ * @param[in/out] requestedSize The target size that the image will be fitted to.
+ * If the source image is smaller than the requested size, the source is not scaled up.
+ * So we reduce the target size while keeping aspect by lowering resolution.
+ * @param[out] scanlinesToCrop The number of scanlines to remove from the image (can be negative to represent Y borders required)
+ * @param[out] columnsToCrop The number of columns to remove from the image (can be negative to represent X borders required)
+ */
+void CalculateBordersFromFittingMode( ImageDimensions sourceSize, FittingMode::Type fittingMode, ImageDimensions& requestedSize, int& scanlinesToCrop, int& columnsToCrop )
+{
+ const unsigned int sourceWidth( sourceSize.GetWidth() );
+ const unsigned int sourceHeight( sourceSize.GetHeight() );
+ const float targetAspect( static_cast< float >( requestedSize.GetWidth() ) / static_cast< float >( requestedSize.GetHeight() ) );
+ int finalWidth = 0;
+ int finalHeight = 0;
+
+ switch( fittingMode )
+ {
+ case FittingMode::FIT_WIDTH:
+ {
+ finalWidth = sourceWidth;
+ finalHeight = static_cast< float >( sourceWidth ) / targetAspect;
+
+ columnsToCrop = 0;
+ scanlinesToCrop = -( finalHeight - sourceHeight );
+ break;
+ }
+
+ case FittingMode::FIT_HEIGHT:
+ {
+ finalWidth = static_cast< float >( sourceHeight ) * targetAspect;
+ finalHeight = sourceHeight;
+
+ columnsToCrop = -( finalWidth - sourceWidth );
+ scanlinesToCrop = 0;
+ break;
+ }
+
+ case FittingMode::SHRINK_TO_FIT:
+ {
+ const float sourceAspect( static_cast< float >( sourceWidth ) / static_cast< float >( sourceHeight ) );
+ if( sourceAspect > targetAspect )
+ {
+ finalWidth = sourceWidth;
+ finalHeight = static_cast< float >( sourceWidth ) / targetAspect;
+
+ columnsToCrop = 0;
+ scanlinesToCrop = -( finalHeight - sourceHeight );
+ }
+ else
+ {
+ finalWidth = static_cast< float >( sourceHeight ) * targetAspect;
+ finalHeight = sourceHeight;
+
+ columnsToCrop = -( finalWidth - sourceWidth );
+ scanlinesToCrop = 0;
+ }
+ break;
+ }
+
+ case FittingMode::SCALE_TO_FILL:
+ {
+ const float sourceAspect( static_cast< float >( sourceWidth ) / static_cast< float >( sourceHeight ) );
+ if( sourceAspect > targetAspect )
+ {
+ finalWidth = static_cast< float >( sourceHeight ) * targetAspect;
+ finalHeight = sourceHeight;
+
+ columnsToCrop = -( finalWidth - sourceWidth );
+ scanlinesToCrop = 0;
+ }
+ else
+ {
+ finalWidth = sourceWidth;
+ finalHeight = static_cast< float >( sourceWidth ) / targetAspect;
+
+ columnsToCrop = 0;
+ scanlinesToCrop = -( finalHeight - sourceHeight );
+ }
+ break;
+ }
+ }
+
+ Uint16Pair finalSize = Uint16Pair( finalWidth, finalHeight );
+ requestedSize = finalSize;
+}
+
+/**
* @brief Construct a bitmap with format and dimensions requested.
*/
BitmapPtr MakeEmptyBitmap( Pixel::Format pixelFormat, unsigned int width, unsigned int height )
}
/**
- * @brief Implement ScaleTofill scaling mode cropping.
+ * @brief Apply cropping and padding for specified fitting mode.
+ *
+ * Once the bitmap has been (optionally) downscaled to an appropriate size, this method performs alterations
+ * based on the fitting mode.
*
- * Implement the cropping required for SCALE_TO_FILL mode,
- * returning a new bitmap with the aspect ratio specified by the scaling mode.
- * This scaling mode selects the central portion of a source image so any spare
- * pixels off one of either the top or bottom edge need to be removed.
+ * This will add vertical or horizontal borders if necessary.
+ * Crop the source image data vertically or horizontally if necessary.
+ * The aspect of the source image is preserved.
+ * If the source image is smaller than the desired size, the algorithm will modify the the newly created
+ * bitmaps dimensions to only be as large as necessary, as a memory saving optimization. This will cause
+ * GPU scaling to be performed at render time giving the same result with less texture traversal.
*
- * @note If the input bitmap was not previously downscaled to exactly encompass
- * the desired output size, the resulting bitmap will have the correct aspect
- * ratio but will have larger dimensions than requested. This can be used to
- * fake the scaling mode by relying on the GPU scaling at render time.
- * If the input bitmap was previously maximally downscaled using a
- * repeated box filter, this is a reasonable approach.
+ * @param[in] bitmap The source bitmap to perform modifications on.
+ * @param[in] desiredDimensions The target dimensions to aim to fill based on the fitting mode.
+ * @param[in] fittingMode The fitting mode to use.
*
- * @return The bitmap passed in if no scaling is needed or possible, else a new,
- * smaller bitmap with the cropping required for the scaling mode applied.
+ * @return A new bitmap with the padding and cropping required for fitting mode applied.
+ * If no modification is needed or possible, the passed in bitmap is returned.
*/
-Integration::BitmapPtr CropForScaleToFill( Integration::BitmapPtr bitmap, ImageDimensions desiredDimensions );
+Integration::BitmapPtr CropAndPadForFittingMode( Integration::BitmapPtr bitmap, ImageDimensions desiredDimensions, FittingMode::Type fittingMode );
+
+/**
+ * @brief Adds horizontal or vertical borders to the source image.
+ *
+ * @param[in] targetPixels The destination image pointer to draw the borders on.
+ * @param[in] bytesPerPixel The number of bytes per pixel of the target pixel buffer.
+ * @param[in] targetDimensions The dimensions of the destination image.
+ * @param[in] padDimensions The columns and scanlines to pad with borders.
+ */
+void AddBorders( PixelBuffer *targetPixels, const unsigned int bytesPerPixel, const ImageDimensions targetDimensions, const ImageDimensions padDimensions );
BitmapPtr ApplyAttributesToBitmap( BitmapPtr bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode )
{
bitmap = DownscaleBitmap( *bitmap, desiredDimensions, fittingMode, samplingMode );
// Cut the bitmap according to the desired width and height so that the
- // resulting bitmap has the same aspect ratio as the desired dimensions:
- if( bitmap && bitmap->GetPackedPixelsProfile() && fittingMode == FittingMode::SCALE_TO_FILL )
+ // resulting bitmap has the same aspect ratio as the desired dimensions.
+ // Add crop and add borders if necessary depending on fitting mode.
+ if( bitmap && bitmap->GetPackedPixelsProfile() )
{
- bitmap = CropForScaleToFill( bitmap, desiredDimensions );
+ bitmap = CropAndPadForFittingMode( bitmap, desiredDimensions, fittingMode );
}
// Examine the image pixels remaining after cropping and scaling to see if all
return bitmap;
}
-BitmapPtr CropForScaleToFill( BitmapPtr bitmap, ImageDimensions desiredDimensions )
+BitmapPtr CropAndPadForFittingMode( BitmapPtr bitmap, ImageDimensions desiredDimensions, FittingMode::Type fittingMode )
{
- const unsigned inputWidth = bitmap->GetImageWidth();
- const unsigned inputHeight = bitmap->GetImageHeight();
- const unsigned desiredWidth = desiredDimensions.GetWidth();
- const unsigned desiredHeight = desiredDimensions.GetHeight();
+ const unsigned int inputWidth = bitmap->GetImageWidth();
+ const unsigned int inputHeight = bitmap->GetImageHeight();
- if( desiredWidth < 1U || desiredHeight < 1U )
+ if( desiredDimensions.GetWidth() < 1u || desiredDimensions.GetHeight() < 1u )
{
- DALI_LOG_WARNING( "Image scaling aborted as desired dimensions too small (%u, %u)\n.", desiredWidth, desiredHeight );
+ DALI_LOG_WARNING( "Image scaling aborted as desired dimensions too small (%u, %u).\n", desiredDimensions.GetWidth(), desiredDimensions.GetHeight() );
}
- else if( inputWidth != desiredWidth || inputHeight != desiredHeight )
+ else if( inputWidth != desiredDimensions.GetWidth() || inputHeight != desiredDimensions.GetHeight() )
{
- const Vector2 desiredDims( desiredWidth, desiredHeight );
-
- // Scale the desired rectangle back to fit inside the rectangle of the loaded bitmap:
- // There are two candidates (scaled by x, and scaled by y) and we choose the smallest area one.
- const float widthsRatio = inputWidth / float(desiredWidth);
- const Vector2 scaledByWidth = desiredDims * widthsRatio;
- const float heightsRatio = inputHeight / float(desiredHeight);
- const Vector2 scaledByHeight = desiredDims * heightsRatio;
- // Trim top and bottom if the area of the horizontally-fitted candidate is less, else trim the sides:
- const bool trimTopAndBottom = scaledByWidth.width * scaledByWidth.height < scaledByHeight.width * scaledByHeight.height;
- const Vector2 scaledDims = trimTopAndBottom ? scaledByWidth : scaledByHeight;
-
- // Work out how many pixels to trim from top and bottom, and left and right:
- // (We only ever do one dimension)
- const unsigned scanlinesToTrim = trimTopAndBottom ? fabsf( (scaledDims.y - inputHeight) * 0.5f ) : 0;
- const unsigned columnsToTrim = trimTopAndBottom ? 0 : fabsf( (scaledDims.x - inputWidth) * 0.5f );
-
- DALI_LOG_INFO( gImageOpsLogFilter, Debug::Concise, "Bitmap, desired(%f, %f), loaded(%u,%u), cut_target(%f, %f), trimmed(%u, %u), vertical = %s.\n", desiredDims.x, desiredDims.y, inputWidth, inputHeight, scaledDims.x, scaledDims.y, columnsToTrim, scanlinesToTrim, trimTopAndBottom ? "true" : "false" );
-
- // Make a new bitmap with the central part of the loaded one if required:
- if( scanlinesToTrim > 0 || columnsToTrim > 0 )
+ // Calculate any padding or cropping that needs to be done based on the fitting mode.
+ // Note: If the desired size is larger than the original image, the desired size will be
+ // reduced while maintaining the aspect, in order to save unnecessary memory usage.
+ int scanlinesToCrop = 0;
+ int columnsToCrop = 0;
+
+ CalculateBordersFromFittingMode( ImageDimensions( inputWidth, inputHeight ), fittingMode, desiredDimensions, scanlinesToCrop, columnsToCrop );
+
+ unsigned int desiredWidth( desiredDimensions.GetWidth() );
+ unsigned int desiredHeight( desiredDimensions.GetHeight() );
+
+ // Action the changes by making a new bitmap with the central part of the loaded one if required.
+ if( scanlinesToCrop != 0 || columnsToCrop != 0 )
{
- const unsigned newWidth = inputWidth - 2 * columnsToTrim;
- const unsigned newHeight = inputHeight - 2 * scanlinesToTrim;
+ // Split the adding and removing of scanlines and columns into separate variables,
+ // so we can use one piece of generic code to action the changes.
+ unsigned int scanlinesToPad = 0;
+ unsigned int columnsToPad = 0;
+ if( scanlinesToCrop < 0 )
+ {
+ scanlinesToPad = -scanlinesToCrop;
+ scanlinesToCrop = 0;
+ }
+ if( columnsToCrop < 0 )
+ {
+ columnsToPad = -columnsToCrop;
+ columnsToCrop = 0;
+ }
+
+ // If there is no filtering, then the final image size can become very large, exit if larger than maximum.
+ if( ( desiredWidth > MAXIMUM_TARGET_BITMAP_SIZE ) || ( desiredHeight > MAXIMUM_TARGET_BITMAP_SIZE ) ||
+ ( columnsToPad > MAXIMUM_TARGET_BITMAP_SIZE ) || ( scanlinesToPad > MAXIMUM_TARGET_BITMAP_SIZE ) )
+ {
+ DALI_LOG_WARNING( "Image scaling aborted as final dimensions too large (%u, %u).\n", desiredWidth, desiredHeight );
+ return bitmap;
+ }
+
+ // Create a new bitmap with the desired size.
BitmapPtr croppedBitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
- Integration::Bitmap::PackedPixelsProfile * packedView = croppedBitmap->GetPackedPixelsProfile();
+ Integration::Bitmap::PackedPixelsProfile *packedView = croppedBitmap->GetPackedPixelsProfile();
DALI_ASSERT_DEBUG( packedView );
const Pixel::Format pixelFormat = bitmap->GetPixelFormat();
- packedView->ReserveBuffer( pixelFormat, newWidth, newHeight, newWidth, newHeight );
-
- const unsigned bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
-
- const PixelBuffer * const srcPixels = bitmap->GetBuffer() + scanlinesToTrim * inputWidth * bytesPerPixel;
- PixelBuffer * const destPixels = croppedBitmap->GetBuffer();
- DALI_ASSERT_DEBUG( srcPixels && destPixels );
-
- // Optimize to a single memcpy if the left and right edges don't need a crop, else copy a scanline at a time:
- if( trimTopAndBottom )
+ packedView->ReserveBuffer( pixelFormat, desiredWidth, desiredHeight, desiredWidth, desiredHeight );
+
+ // Add some pre-calculated offsets to the bitmap pointers so this is not done within a loop.
+ // The cropping is added to the source pointer, and the padding is added to the destination.
+ const unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
+ const PixelBuffer * const sourcePixels = bitmap->GetBuffer() + ( ( ( ( scanlinesToCrop / 2 ) * inputWidth ) + ( columnsToCrop / 2 ) ) * bytesPerPixel );
+ PixelBuffer * const targetPixels = croppedBitmap->GetBuffer();
+ PixelBuffer * const targetPixelsActive = targetPixels + ( ( ( ( scanlinesToPad / 2 ) * desiredWidth ) + ( columnsToPad / 2 ) ) * bytesPerPixel );
+ DALI_ASSERT_DEBUG( sourcePixels && targetPixels );
+
+ // Copy the image data to the new bitmap.
+ // Optimize to a single memcpy if the left and right edges don't need a crop or a pad.
+ unsigned int outputSpan( desiredWidth * bytesPerPixel );
+ if( columnsToCrop == 0 && columnsToPad == 0 )
{
- memcpy( destPixels, srcPixels, newHeight * newWidth * bytesPerPixel );
+ memcpy( targetPixelsActive, sourcePixels, ( desiredHeight - scanlinesToPad ) * outputSpan );
}
else
{
- for( unsigned y = 0; y < newHeight; ++y )
+ // The width needs to change (due to either a crop or a pad), so we copy a scanline at a time.
+ // Precalculate any constants to optimize the inner loop.
+ const unsigned int inputSpan( inputWidth * bytesPerPixel );
+ const unsigned int copySpan( ( desiredWidth - columnsToPad ) * bytesPerPixel );
+ const unsigned int scanlinesToCopy( desiredHeight - scanlinesToPad );
+
+ for( unsigned int y = 0; y < scanlinesToCopy; ++y )
{
- memcpy( &destPixels[y * newWidth * bytesPerPixel], &srcPixels[y * inputWidth * bytesPerPixel + columnsToTrim * bytesPerPixel], newWidth * bytesPerPixel );
+ memcpy( &targetPixelsActive[ y * outputSpan ], &sourcePixels[ y * inputSpan ], copySpan );
}
}
- // Overwrite the loaded bitmap with the cropped version:
+ // Add vertical or horizontal borders to the final image (if required).
+ AddBorders( croppedBitmap->GetBuffer(), bytesPerPixel, ImageDimensions( desiredWidth, desiredHeight ), ImageDimensions( columnsToPad, scanlinesToPad ) );
+
+ // Overwrite the loaded bitmap with the cropped version
bitmap = croppedBitmap;
}
}
return bitmap;
}
+void AddBorders( PixelBuffer *targetPixels, const unsigned int bytesPerPixel, const ImageDimensions targetDimensions, const ImageDimensions padDimensions )
+{
+ // Assign ints for faster access.
+ unsigned int desiredWidth( targetDimensions.GetWidth() );
+ unsigned int desiredHeight( targetDimensions.GetHeight() );
+ unsigned int columnsToPad( padDimensions.GetWidth() );
+ unsigned int scanlinesToPad( padDimensions.GetHeight() );
+ unsigned int outputSpan( desiredWidth * bytesPerPixel );
+
+ // Add letterboxing (symmetrical borders) if needed.
+ if( scanlinesToPad > 0 )
+ {
+ // Add a top border. Note: This is (deliberately) rounded down if padding is an odd number.
+ memset( targetPixels, BORDER_FILL_VALUE, ( scanlinesToPad / 2 ) * outputSpan );
+
+ // We subtract scanlinesToPad/2 from scanlinesToPad so that we have the correct
+ // offset for odd numbers (as the top border is 1 pixel smaller in these cases.
+ unsigned int bottomBorderHeight = scanlinesToPad - ( scanlinesToPad / 2 );
+
+ // Bottom border.
+ memset( &targetPixels[ ( desiredHeight - bottomBorderHeight ) * outputSpan ], BORDER_FILL_VALUE, bottomBorderHeight * outputSpan );
+ }
+ else if( columnsToPad > 0 )
+ {
+ // Add a left and right border.
+ // Left:
+ // Pre-calculate span size outside of loop.
+ unsigned int leftBorderSpanWidth( ( columnsToPad / 2 ) * bytesPerPixel );
+ for( unsigned int y = 0; y < desiredHeight; ++y )
+ {
+ memset( &targetPixels[ y * outputSpan ], BORDER_FILL_VALUE, leftBorderSpanWidth );
+ }
+
+ // Right:
+ // Pre-calculate the initial x offset as it is always the same for a small optimization.
+ // We subtract columnsToPad/2 from columnsToPad so that we have the correct
+ // offset for odd numbers (as the left border is 1 pixel smaller in these cases.
+ unsigned int rightBorderWidth = columnsToPad - ( columnsToPad / 2 );
+ PixelBuffer * const destPixelsRightBorder( targetPixels + ( ( desiredWidth - rightBorderWidth ) * bytesPerPixel ) );
+ unsigned int rightBorderSpanWidth = rightBorderWidth * bytesPerPixel;
+
+ for( unsigned int y = 0; y < desiredHeight; ++y )
+ {
+ memset( &destPixelsRightBorder[ y * outputSpan ], BORDER_FILL_VALUE, rightBorderSpanWidth );
+ }
+ }
+}
+
Integration::BitmapPtr DownscaleBitmap( Integration::Bitmap& bitmap,
ImageDimensions desired,
FittingMode::Type fittingMode,
#include <queue>
#include <cstring>
#include <dali/devel-api/common/map-wrapper.h>
-#include <dali/devel-api/common/mutex.h>
+#include <dali/devel-api/threading/mutex.h>
// INTERNAL HEADERS
#include <dali/integration-api/bitmap.h>